【发布时间】:2021-09-06 11:15:06
【问题描述】:
我正在尝试将仅具有 int 字段(ushort、ulong、uint、int 等)的对象转换为一个字节数组,其中包含每个 int 作为一个字节,按照它在对象中出现的顺序。 例如,如果我有一个表单对象
obj = {subobj: {uint firstProp: 500, ushort secondProp: 12}, byte lastProp: 5}
那么我希望字节数组是
{0, 0, 1, 244, 0, 12, 5}
我尝试使用序列化创建这个字节数组(如this answer 中所述),但我注意到每个字节前后都有一堆东西。基于this website,我相信这代表了我不想要的数据库和文件。
我知道在 C++ 中我可以使用 reinterpret_cast<uint8_t*>(obj) 来获得所需的结果。在 C# 中是否有等效的方法来执行此操作?
【问题讨论】:
-
不幸的是
Buffer.BlockCopy不支持聚合类型,即使只包含原始成员并且应该是 blittable。如果您愿意使用/unsafe进行编译,您可以使用Marshal.PtrToStructure及其反函数。 -
我强烈建议您不要这样做,因为底层表示可能会在不同的架构上发生变化。您可以查看stackoverflow.com/questions/3278827/… 和docs.microsoft.com/en-us/dotnet/standard/native-interop/… 以获取有关不安全编组功能的信息,但您需要使用/unsafe 进行编译,正如@BenVoigt 所说。这些功能仅适用于结构。更好的方法是为这种类型编写自己的序列化器方法,将 BinaryWriter 作为参数。
-
@StevePick:底层表示非常明确,p/invoke 已经依赖它。如果您对默认设置不满意,可以使用
StructLayout.Explicit和FieldOffsetAttribute进行完全控制。 -
@BenVoigt 哦,酷,我想编译器/运行时没有任何不同的架构或实现,那么?我链接了关于自定义结构布局的文档,以表明在绝对必要的情况下可以完成这些事情,但我仍然更喜欢安全路线。不过,要写很多烦人的样板。
-
@StevePick:默认设计是为了能够匹配 C 中定义的类型,并以与 C 结构完全相同的方式在平台间变化。自然地,任何
IntPtr成员都会在平台之间改变大小,其他成员在任何地方都是相同的大小,但可能会改变对齐方式(因此内部填充)。但是,如果您的目标是平台之间的互操作性而不是原生 C 代码,只需在 StructLayoutAttribute 上设置Pack=1即可禁用特定于平台的对齐/填充。
标签: c# arrays casting binary integer