从 属性 不安全且固定的返回 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 正确的值