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 移动?
一个(更简单?)的解决方案:
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 要求。