如何创建使用“in”而不是“ref”参数的“MemoryMarshal.CreateReadOnlySpan”方法?

Mat*_*mas 5 c#

MemoryMarshal.CreateReadOnlySpan有这个签名:

public static ReadOnlySpan<T> CreateReadOnlySpan<T> (ref T reference, int length);
Run Code Online (Sandbox Code Playgroud)

请注意,它需要一个ref参数。换句话说,你不能用它来执行此操作:

[StructLayout(LayoutKind.Sequential, Size = 512)]
struct LargeStruct
{}

class Program
{
    static readonly LargeStruct Blob = default;
    
    static byte GetSomethingFrom(in LargeStruct blob)
    {
        ReadOnlySpan<byte> span = MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(in blob, 1));
        //                                                                               ^^^^^^^ Argument is 'in' while parameter is declared as 'ref'
        return span[5];
    }

    static void Main()
    {
        Console.WriteLine(GetSomethingFrom(in Blob));
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,我不能接受 a,ref因为Blob它是只读字段。

所以我只能做这样的事情:

[StructLayout(LayoutKind.Sequential, Size = 512)]
struct LargeStruct
{}

class Program
{
    static readonly LargeStruct Blob = default;

    static unsafe byte GetSomethingFrom(in LargeStruct blob)
    {
        fixed(LargeStruct* pointer = &blob)
        {
            ReadOnlySpan<byte> span = MemoryMarshal.AsBytes(new ReadOnlySpan<LargeStruct>(pointer, 1));
            return span[5];
        }
    }

    static void Main()
    {
        Console.WriteLine(GetSomethingFrom(in Blob));
    }
}
Run Code Online (Sandbox Code Playgroud)

我想知道是否可以将此行为封装到具有以下签名的方法中:

public static ReadOnlySpan<T> CreateReadOnlySpan<T> (in T reference, int length);
Run Code Online (Sandbox Code Playgroud)

我的尝试

到目前为止,这是我的尝试:

using System;
using System.Runtime.CompilerServices;

public static class MemoryMarshal2
{
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static unsafe ReadOnlySpan<T> CreateReadOnlySpan<T>(in T value, int length)
        where T : unmanaged
    {
        fixed(T* pointer = &value)
        {
            return new ReadOnlySpan<T>(pointer, length);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,我不确定fixed关键字的这种用法是否合适。文档

指向可移动托管变量的指针仅在上下文中才有用fixed

...但在这里我将指针从fixed上下文中“泄漏”出来(通过返回的ReadOnlySpan)。我认为上面例子中的变量Blob可以被 GC 移动?

Mat*_*mas 1

一个(更简单?)的解决方案:

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

public static class MemoryMarshal2
{
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static ReadOnlySpan<T> CreateReadOnlySpan<T>(in T value, int length) =>
        MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in value), length);
}
Run Code Online (Sandbox Code Playgroud)

不需要unsafe,而且几乎完全符合MemoryMarshal.CreateReadOnlySpan 要求