C# 获得Span<;字节>;在不复制结构的情况下覆盖结构
我一直在试验C# 获得Span<;字节>;在不复制结构的情况下覆盖结构,c#,system.io.pipelines,C#,System.io.pipelines,我一直在试验Span作为ReadOnlySequence和System.IO.pipeline的一部分 我目前正在尝试通过struct获取Span,而不使用unsafe代码,也不复制该struct 我的结构很简单: [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode)] public struct Packet { public byte TestByte;
Span
作为ReadOnlySequence
和System.IO.pipeline的一部分
我目前正在尝试通过struct
获取Span
,而不使用unsafe
代码,也不复制该struct
我的结构很简单:
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode)]
public struct Packet
{
public byte TestByte;
}
方法1——有效——但感觉“不安全”
但是我所拥有的ToByteArray()的任何当前实现仍在制作数据包结构的副本
我不能做像这样的事情:
Span<byte> packetSpan = (byte[])packet;
// ^^ Won't compile
Span packetSpan=(字节[])数据包;
//^^无法编译
如果没有不安全
,就无法在任意结构上获取Span
,因为这样的Span将允许您以任何方式更改结构的任何位,可能会违反类型的不变量-这本质上是一个不安全的操作
好的,但是如何处理ReadOnlySpan
?请注意,您必须将StructLayoutAttribute
放在您的结构上,这样代码才有意义。这应该是一个暗示。想象一下,尝试编写一个更简单的方法,该方法为任意T(其中T:struct
)返回一个byte[]
。你必须先找出结构的大小,不是吗?那么,如何计算C#中结构的大小呢?您可以使用sizeof
操作符,该操作符需要unsafe
上下文,并且需要将结构作为;或者,您也可以选择不可靠的、仅适用于具有顺序或显式字节布局的结构没有安全、通用的方法,因此您不能这样做
Span
和ReadOnlySpan
在设计时并没有考虑访问结构字节,而是考虑了数组的跨段,这些数组具有已知的大小并保证是顺序的
如果你确信自己知道自己在做什么,那么你可以在不安全的环境中这样做——这就是它的目的。但是请注意,基于上述原因,您使用不安全的解决方案不会推广到任意结构
如果您打算将结构用作IO操作的缓冲区,您可能需要研究一下。它们还需要不安全的
上下文,但您可以将不安全性封装在结构中,并将Span
返回到该固定缓冲区。基本上,任何处理内存中对象字节结构的操作都需要.NET中的不安全
,因为内存管理就是这个“安全”所指的东西。你必须以安全的方式进行,因为从这个词的真正含义来看,它是不安全的,因为如果你不够小心,你会朝自己的脚开枪。原因如下:
考虑以下代码:
Span<byte> GiveMeSpan()
{
MyLovelyStruct value = new MyLovelyStruct();
unsafe
{
return new Span<byte>(&value, sizeof(MyLovelyStruct));
}
}
当Process()
方法正在处理您的mylovelstruct
和mylovelclass
在内存中突然移动时(是的,内存中GC move的对象,)会发生一个错误?是的,指向mylovelstruct
的Span
将不再指向新的mylovelstruct
地址,您的程序将损坏
因此,为了使用Span
或任何其他指针类型安全地包装struct
,您必须确保:
- 实例位于固定的内存位置(例如,在堆栈或非托管内存中,如由分配的内存块)
- 在完成指针操作之前,不会声明实例内存
因此,需要不安全的关键字,即使您可以绕过它,也要由您向代码的读者发出警告。我认为您可以编写用户定义的转换运算符。我很确定,如果没有不安全
,一般来说,对于一个结构来说,没有办法做到这一点,因为如果你在一个结构的所有字节上获得一个Span
,你就有可能以任何方式改变该结构中的任何位,这本身就是不安全的。这两个都是完美的答案。谢谢你的努力,我真的很感谢你的努力,我需要选择一个作为答案,尽管我想选择两者。所以我担心这是我的RNG的一个例子。这两个都是完美的答案。谢谢你的努力,我真的很感激你的努力,还有那些指向固定大小缓冲区的指针。我需要选择一个作为答案,虽然我想选择两者。因此,我担心这是我的RNG的一个案例。
Span<byte> packetSpan = new Packet().ToByteArray();
Span<byte> packetSpan = (byte[])packet;
// ^^ Won't compile
Span<byte> GiveMeSpan()
{
MyLovelyStruct value = new MyLovelyStruct();
unsafe
{
return new Span<byte>(&value, sizeof(MyLovelyStruct));
}
}
class MyLovelyClass
{
private MyLovelyStruct value;
public void Foo()
{
unsafe
{
var span = new Span(&value, sizeof(MyLovelyStruct));
Process(span);
}
}
}
// Declaration
Process(Span<byte> span);