Home > OS >  Returning Span from a Property With Unsafe and Fixed
Returning Span from a Property With Unsafe and Fixed

Time:12-20

I came across something very much like the below at work. I have never worked with a C# codebase that makes such heavy use of structs before.

I have used fixed before to prevent the garbage collector from moving things while I work on something unsafe using pointers. But I've never seen it used while taking a pointer and passing it to a Span like this and then using the Span outside of the fixed statement.

Is this okay? I guess since Span is managed, once we pass the location to it, then if the GC moves the location of MyStruct, it should get the new location okay right?

[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);
            }
        }
    }
}

CodePudding user response:

This is the source code in .NET 6

public unsafe Span(void* pointer, int length)
{
    _pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref *(byte*)pointer));
    _length = length;
}

Your code:

fixed (MyInnerStruct* ptr = &Value0)
{
    return new Span<MyInnerStruct>(ptr, ValidValueCount);
}

I did some tests, and using the span like you did is always safe to do even when the PTR gets moved around by the garbarge collector.

I also tested to write to the Span after the ptr had been moved and the original object was still correctly updated.

The Span will always return the correct values because of the ByReference

  • Related