考虑以下结构:
internal struct WriteBuffer64
{
private const int INLINE_BUFFER_SIZE = 64;
private unsafe fixed byte buffer[INLINE_BUFFER_SIZE];
private int used;
public unsafe Span<byte> GetWriteSpan(int toWrite)
{
if (used + toWrite > INLINE_BUFFER_SIZE)
throw new Exception(...);
int offset = used;
used += toWrite;
return MemoryMarshal.CreateSpan(ref buffer[offset], toWrite);
}
// ...
}
我想知道这样做是否安全。当装箱或在类类型中使用时,
WriteBuffer
的实例可能位于堆上。因此,我假设本机 byte*
指针(指向固定缓冲区)可能无法安全使用。
但是
Span
怎么样?是否能够将其解释为对托管对象的引用?更一般地说,Spans 中托管对象的引用的魔力是如何发挥作用的?
不。结构体通常在堆栈上分配。这个例子说明了为什么它不安全。
void Main() {
var span = GetMeSpan();
var beforeMethodCall = string.Join(" ", span.ToArray());
Console.WriteLine("Just to use the stack");
var afterMethodCall = string.Join(" ", span.ToArray());
Console.WriteLine(beforeMethodCall);
Console.WriteLine(afterMethodCall);
}
Span<byte> GetMeSpan() {
var buffer = new WriteBuffer64();
return buffer.GetWriteSpan(42);
}
输出:
Just to use the stack
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 70
64 203 27 0 0 0 0 0 10 159 84 231 254 7 0 0 160 170 74 66 1 0 0 0 0 0 0 0 0 0 0 0 192 0 206 65 1 0 0 0 13 70