C# 不安全代码错误,使用指针读取内存

C# 不安全代码错误,使用指针读取内存,c#,memory,unsafe,unsafe-pointers,C#,Memory,Unsafe,Unsafe Pointers,内存中有一个二进制序列化对象,我想使用C#中的指针(unsafae代码)从内存中读取它。请看下面从内存流读取的函数 static Results ReadUsingPointers(byte[] data) { unsafe { fixed (byte* packet = &data[0]) { return *(Results*)packet; } } } 在此返回*(结果*)数据包语句我

内存中有一个二进制序列化对象,我想使用C#中的指针(unsafae代码)从内存中读取它。请看下面从内存流读取的函数

static Results ReadUsingPointers(byte[] data)
{
    unsafe
    {
        fixed (byte* packet = &data[0])
        {
            return *(Results*)packet;
        }
    }
}
在此
返回*(结果*)数据包语句我得到编译时异常“无法获取托管类型结果的地址、大小或声明指向托管类型结果的指针”

这是我的结构

public struct Results
{
    public int Id;
    public int Score;
    public char[] Product;
}
根据我的理解,我的结构的所有属性都是可blittable属性,那么为什么我会出现这个错误,如果我需要在我的结构中使用char[],我应该怎么做

编辑-1 让我进一步解释一下(请注意,对象是模拟的)

背景: 我有一个
结果
对象数组,我使用二进制序列化对它们进行序列化。现在,在我的程序的后期阶段,我需要尽快反序列化内存中的数据,因为数据量非常大。所以我在尝试,不安全的代码可以如何帮助我

假设我的结构不包括
publicchar[]产品,我以相当快的速度取回数据。但对于char[],它会给我错误(编译器应该这样做)。我想找到一个在这种情况下使用char[]的解决方案。

:

以下任何类型都可以是指针类型:

  • sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、decimal或bool

  • 任何枚举类型

  • 任何指针类型

  • 仅包含非托管类型字段的任何用户定义的结构类型

因此,您可以按如下方式定义结构以修复编译器错误:

public struct Results
{
    public int Id;
    public int Score;
    // Don't actually do this though.
    public unsafe char* Product;
}
这样,就可以指向数组的第一个元素

但是,根据您编辑的问题,您需要一种不同的方法

我有一个结果对象数组,我使用二进制序列化来序列化它们。现在,在程序的后期阶段,我需要尽快对内存中的数据进行反序列化


通常您会使用
BinaryFormatter
来实现此目的。如果这太慢,那么问题应该是是否可以首先避免序列化

你不能指望这会奏效

public struct Results
{
    public int Id;
    public int Score;
    public char[] Product;
}
char[]
array
Product
是一种托管类型。您的代码尝试使用类型
结果*
。这是指针类型。可以声明的状态指向以下任意一个指针:

  • sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、decimal或bool
  • 任何枚举类型
  • 任何指针类型
  • 仅包含非托管类型字段的任何用户定义的结构类型
现在,您的结构显然与前三个项目都不匹配。并且与最后一个项目符号也不匹配,因为该数组是托管类型

根据我的理解,我的结构的所有属性都是可blittable属性

是的,这是事实,但并不相关。您需要结构的成员具有更大的可blittable性


即使您的代码可以编译,您会如何想象它可以工作?请考虑这个表达式:

*(Results*)packet
编译器如何将其转换为创建新数组并复制正确数量的数组元素?很明显,编译器不希望在这里做任何有用的事情,这就是语言拒绝您的代码的原因

我不认为不安全的代码会在这里帮助你。序列化数组时,必须序列化长度,然后序列化数组的内容。要反序列化,需要读取长度,创建该长度的新数组,然后读取内容。不安全代码对此无能为力。静态定义类型的简单内存副本没有用处,因为这意味着数组的长度在编译时已知。事实并非如此


关于你的更新,你说:

我有一个使用二进制序列化的结果对象数组

为了反序列化,您需要了解二进制序列化详细布局的代码。问题中的代码无法执行此操作

您可能还不了解的是,您不能期望复制任意内存块,这些内存块的长度是可变的,并且只有在运行时才知道,而实际上不知道这些长度。实际上,您希望能够在系统中不知道要复制多少的情况下复制内存


使用不安全的类型转换和内存副本进行反序列化的尝试无法工作。如果不考虑序列化的二进制格式,就无法获得更详细的帮助。

答案的第一部分是准确的。但第二部分肯定包含了不好的建议。我所遇到的任何序列化都不是通过编写指向字节流的指针来进行操作的。@DavidHeffernan确实,序列化是非常不寻常的。这只是编译器错误的解决方案。当然还有其他方法可以正确序列化,但我们可能需要更多地了解这里正在阅读的数据结构。我对您的回答的问题是,它似乎支持使用
不安全字符*
,而这肯定是错误的问题解决方案。我不喜欢你的答案会那样。@DavidHeffernan我稍微调整了一下我的答案,也许我们会从作者那里得到更多的细节来建议一个合适的解决方案。我仍然不喜欢使用
不安全字符*
的建议。一个天真的读者会认为这是一个好主意,但肯定不是。你为什么保留它?你能告诉我们更多关于你试图读取的数据吗?否则很难判断如何正确处理数组数据。我同意你的观点,但我有一个定义的长度,例如,
public char[256]Product那么我是否有可能通过使用指针或任何