The following code causes the compiler to throw error CS1605 ("Cannot pass 'var' as a ref or out argument because it is read-only") in the first line of the property getter.
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public readonly struct MyStruct
{
public readonly int Field1;
public readonly int Field2;
public MyStruct(int field1, int field2) => (Field1, Field2) = (field1, field2);
public ReadOnlySpan<byte> Span
{
get
{
// This code only works when MyStruct is not read only
ReadOnlySpan<MyStruct> temp = MemoryMarshal.CreateReadOnlySpan(ref this, 1);
return MemoryMarshal.Cast<MyStruct, byte>(temp);
}
}
}
Run Code Online (Sandbox Code Playgroud)
Removing the readonly
from the public readonly struct MyStruct
line makes the code work, but for performance reasons, I would really like the struct to be readonly
. It makes the code so much more cleaner than having to pass the struct as ref
all the time.
Is there a way to get a ReadOnlySpan<byte>
from a readonly struct?
Edit: ... without creating an implicit or explicit copy of the structure?
看起来像这样:
// The following code will work from C# 7.3 and up, no unsafe keyword required
Span<MyStruct> span = stackalloc MyStruct[1];
span[0] = new MyStruct(3, 4);
var bytes = MemoryMarshal.Cast<MyStruct, byte>(span);
Run Code Online (Sandbox Code Playgroud)
如果我们想将其作为属性公开,我们可以尝试以下操作:
// Will not work at runtime
public ReadOnlySpan<byte> Span
{
get
{
unsafe
{
fixed (MyStruct* ptr = &this)
{
return new ReadOnlySpan<byte>(ptr, sizeof(MyStruct)); // If on the heap, we're doomed as returning will unpin the memory.
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
并将结构标记为 a readonly ref struct
,这再次保护了我们在堆上的结构。这会编译,但不会像您AccessViolationException
在运行时获得的那样运行。我会做更多的挖掘,看看是否有可能,这样做在逻辑上应该是安全的,但今天可能不可能。
另一个折衷解决方案是将其保留为readonly struct
(not ref struct
) 并添加此静态方法:
public static unsafe ReadOnlySpan<byte> GetSpan(ref MyStruct myStruct)
{
return new ReadOnlySpan<byte>(Unsafe.AsPointer(ref myStruct), sizeof(MyStruct));
}
Run Code Online (Sandbox Code Playgroud)
然后从调用代码:
var myStruct = new MyStruct(1, 2);
var span = MyStruct.GetSpan(ref myStruct);
Run Code Online (Sandbox Code Playgroud)
我们可以通过将它移到 ref 扩展方法(AC# 7.2 功能)中来改进它的使用:
class Program
{
static void Main()
{
var myStruct = new MyStruct(1, 2);
var span = myStruct.GetSpan();
}
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public readonly struct MyStruct
{
public readonly int Field1;
public readonly int Field2;
public MyStruct(int field1, int field2) => (Field1, Field2) = (field1, field2);
}
public static class MyStructExtensions
{
public static unsafe ReadOnlySpan<byte> GetSpan(ref this MyStruct myStruct)
{
return new ReadOnlySpan<byte>(Unsafe.AsPointer(ref myStruct), sizeof(MyStruct));
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
122 次 |
最近记录: |