从 属性 不安全且固定的返回 Span
Returning Span from a Property With Unsafe and Fixed
我在工作中遇到了与下面非常相似的事情。我以前从未使用过如此大量使用结构的 C# 代码库。
我之前使用 fixed 来防止垃圾收集器在我使用指针处理不安全的事情时移动东西。但是我从来没有见过它在获取指针并将其传递给像这样的 Span 然后在 fixed 语句之外使用 Span 时使用它。
这样可以吗?我想既然 Span 是托管的,一旦我们将位置传递给它,那么如果 GC 移动 MyStruct 的位置,它应该得到新的位置好吗?
[StructLayout(LayoutKind.Sequential)]
public unsafe struct MyInnerStruct
{
public uint InnerValueA;
public uint InnerValueB;
public float InnerValueC;
public long InnerValueD;
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct MyStruct
{
public MyInnerStruct Value0;
public MyInnerStruct Value1;
public MyInnerStruct Value2;
public MyInnerStruct Value3;
public MyInnerStruct Value4;
public MyInnerStruct Value5;
public MyInnerStruct Value6;
public MyInnerStruct Value7;
public MyInnerStruct Value8;
public MyInnerStruct Value9;
public int ValidValueCount;
public Span<MyInnerStruct> Values
{
get
{
fixed (MyInnerStruct* ptr = &Value0)
{
return new Span<MyInnerStruct>(ptr, ValidValueCount);
}
}
}
}
这是 .NET 6 中的源代码
public unsafe Span(void* pointer, int length)
{
_pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref *(byte*)pointer));
_length = length;
}
您的代码:
fixed (MyInnerStruct* ptr = &Value0)
{
return new Span<MyInnerStruct>(ptr, ValidValueCount);
}
我做了一些测试,像你一样使用跨度总是安全的,即使 PTR 被垃圾收集器四处移动。
我还测试了在移动 ptr 并且原始对象仍然正确更新后写入 Span
。
由于 ByReference
,Span 将始终 return 正确的值
我在工作中遇到了与下面非常相似的事情。我以前从未使用过如此大量使用结构的 C# 代码库。
我之前使用 fixed 来防止垃圾收集器在我使用指针处理不安全的事情时移动东西。但是我从来没有见过它在获取指针并将其传递给像这样的 Span 然后在 fixed 语句之外使用 Span 时使用它。
这样可以吗?我想既然 Span 是托管的,一旦我们将位置传递给它,那么如果 GC 移动 MyStruct 的位置,它应该得到新的位置好吗?
[StructLayout(LayoutKind.Sequential)]
public unsafe struct MyInnerStruct
{
public uint InnerValueA;
public uint InnerValueB;
public float InnerValueC;
public long InnerValueD;
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct MyStruct
{
public MyInnerStruct Value0;
public MyInnerStruct Value1;
public MyInnerStruct Value2;
public MyInnerStruct Value3;
public MyInnerStruct Value4;
public MyInnerStruct Value5;
public MyInnerStruct Value6;
public MyInnerStruct Value7;
public MyInnerStruct Value8;
public MyInnerStruct Value9;
public int ValidValueCount;
public Span<MyInnerStruct> Values
{
get
{
fixed (MyInnerStruct* ptr = &Value0)
{
return new Span<MyInnerStruct>(ptr, ValidValueCount);
}
}
}
}
这是 .NET 6 中的源代码
public unsafe Span(void* pointer, int length)
{
_pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref *(byte*)pointer));
_length = length;
}
您的代码:
fixed (MyInnerStruct* ptr = &Value0)
{
return new Span<MyInnerStruct>(ptr, ValidValueCount);
}
我做了一些测试,像你一样使用跨度总是安全的,即使 PTR 被垃圾收集器四处移动。
我还测试了在移动 ptr 并且原始对象仍然正确更新后写入 Span
。
由于 ByReference