Итак, я провел некоторые исследования в виде сборок ILSpy .NET и некоторое тестирование на .NET Core 2.1.Результаты моего теста следующие:
interface ITest
{
Span<byte> Data { get; }
}
unsafe struct TestStruct : ITest
{
fixed byte dataField[8];
public Span<byte> Data
{
get
{
//Unsafe.AsPointer() to avoid the fixed expression :-)
return new Span<byte>(Unsafe.AsPointer(ref dataField[0]), 8);
}
}
}
class Program
{
//Note: This test is done in Debug mode to make sure the string allocation isn't ommited
static void Main(string[] args)
{
new string('c', 200);
//Boxes the struct onto the heap.
//The object is allocated after the string to ensure it will be moved during GC compacting
ITest HeapAlloc = new TestStruct();
Span<byte> span1, span2;
span1 = HeapAlloc.Data; //Creates span to old location
GC.Collect(2, GCCollectionMode.Forced, true, true); //Force a compacting garbage collection
span2 = HeapAlloc.Data; //Creates span to new location
//Ensures that if the pointer to span1 wasn't updated, that there wouldn't be heap corruption
//Write to Span2
span2[0] = 5;
//Read from Span1
Console.WriteLine(span1[0] == 5); //Prints true in .NET Core 2.1, span1's pointer is updated
}
}
Что я узнал из моего исследования IL, пожалуйста, прости меня, если я не правильно объясняю это:
.NET Core 2Span Field Span:
//Note, this is not the complete declaration, just the fields
public ref readonly struct Span<T>
{
internal readonly ByReference<T> _pointer;
private readonly int _length;
}
.NET Framework 3 Field Span:
//Same note as 2 Field Span
public ref readonly struct Span<T>
{
private readonly Pinnable<T> _pinnable;
private readonly IntPtr _byteOffset;
private readonly int _length;
}
.Net Core использует 2-полевую модель Span.Из-за .NET Framework, использующего модель 3 полей, его указатель не будет обновлен.Причина?Конструктор Span<T>(void* pointer, int length)
(который я использую для этого) для диапазона 3 полей устанавливает поле _byteOffset
с аргументом pointer
.Указатель в диапазоне 3 полей, который будет обновлен GC, является полем _pinnable
.С 2 полями Span они одинаковы.
Итак, ответ на мой вопрос: да, у меня может быть точка Span на фиксированный буфер с фиксированным оператором или без него, но это опасно делатьвообще, когда не используется .NET Core 2 Span Model.Поправьте меня, если я ошибаюсь в текущей модели Span .NET Framework.