在二进制紧凑格式中序列化结构体

3
在C#中,有一种方法可以将结构体序列化为二进制流(MemoryStream),使得二进制表示与结构体的可视布局等效(即没有填充)吗?
在C/C++中,您可以使用#pragma命令告诉编译器将结构体紧密打包,以便字段之间没有填充。如果您有两个应用程序通过套接字来回传递消息,这很有帮助。禁用紧密打包后,您只需"发送"结构体的内容到套接字上,就不必担心将每个字段单独打包到二进制缓冲区中(如果必要还必须进行大小端交换)。
2个回答

3

除非您使用不安全的代码,否则不行。使用Protocol Buffers或Thrift或类似的东西;根据我的经验,我不建议使用基于.NET内置二进制序列化的方法。您还可以使用 BinaryWriter/BinaryReader 进行序列化/反序列化(使用反射或预先生成序列化代码)。至于打包,您可以使用[StructLayout]属性来控制它。


有关信息 - protobuf-net不支持结构体(仅支持类),我相信dotnet-protobufs也是如此。至于Thrift,我不清楚。 - Marc Gravell

1
你可以使用 [StructLayout][FieldOffset] 属性来控制结构体字段的打包方式(有关更多信息,请搜索“marshalling”),然后使用以下代码生成可通过网络流发送的结构体的二进制表示形式:
public static byte[] GetBytes<TStruct>(TStruct data) where TStruct : struct
{
    int structSize = Marshal.SizeOf(typeof(TStruct));
    byte[] buffer = new byte[structSize];
    GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
    Marshal.StructureToPtr(data, handle.AddrOfPinnedObject(), false);
    handle.Free();
    return buffer;
}

缺点:

  • 它不是.NET的惯用语
  • 您需要非托管代码权限
  • 缓冲区固定可能会影响性能
  • 您的结构体不能有引用(字符串和数组有特殊情况)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接