C# 结构调整建议?

C# 结构调整建议?,c#,.net,memory,struct,C#,.net,Memory,Struct,我正在通过网络发送数据。要通过网络发送数据,我将其打包到字节数组中 现在,数据类型由一个字节和3个浮点组成,总共13个字节。要阅读这篇文章,我需要知道结构的大小。使用封送处理的sizeOf不会返回序列化字节数组的“正确”大小 现在我知道发生了什么。Marshal正在返回我的结构的托管对齐大小。我也知道我是否标记它 [StructLayout(LayoutKind.Sequential, Pack = 1)] 然后它将返回“正确”的大小。我的问题是什么是最好的方法?我知道它添加填充位的原因是因

我正在通过网络发送数据。要通过网络发送数据,我将其打包到字节数组中

现在,数据类型由一个字节和3个浮点组成,总共13个字节。要阅读这篇文章,我需要知道结构的大小。使用封送处理的sizeOf不会返回序列化字节数组的“正确”大小

现在我知道发生了什么。Marshal正在返回我的结构的托管对齐大小。我也知道我是否标记它

 [StructLayout(LayoutKind.Sequential,
Pack = 1)]
然后它将返回“正确”的大小。我的问题是什么是最好的方法?我知道它添加填充位的原因是因为处理器希望所有内容都对齐(如果我没有弄错,请随意更正!)

性能损失值得这么做吗?这样我就可以使用sizeof来反序列化数组,还是使用一个我自己计算的常量来读取数组,或者通过填充数组(我最不喜欢的选项)在数组中接受几个字节的大小损失更好

如果我对Marshal为什么要对齐内存或其他任何东西有误解,请随时启发我,并就哪种方法是最好的给我建议

我正在通过网络发送数据。要通过网络发送数据,我将其打包到字节数组中

不要这样做

Marshal
StructLayout
用于本机互操作,而不是用于网络IO和串行化

为IO序列化对象实例的正确方法是手动写入,这样可以精确控制序列化表示,并保证格式正确(多字节值的尾数)。使用
BinaryWriter
(或者更好的方法是使用Jon Skeet的
MiscUtil.EndianBinaryReader
:)

可以将其视为一种可序列化的
iseralizable
-lite。您可以在网络程序中使用它,方法是拥有一个与开放式网络套接字连接对应的
对象,然后将其环绕在
EndianBinaryWriter | Reader
对象周围,并通过这些对象执行所有IO操作。作为奖励,您可以免费获得磁盘序列化:只需使用
FileStream
而不是网络流

我正在通过网络发送数据。要通过网络发送数据,我将其打包到字节数组中

不要这样做

Marshal
StructLayout
用于本机互操作,而不是用于网络IO和串行化

为IO序列化对象实例的正确方法是手动写入,这样可以精确控制序列化表示,并保证格式正确(多字节值的尾数)。使用
BinaryWriter
(或者更好的方法是使用Jon Skeet的
MiscUtil.EndianBinaryReader
:)


可以将其视为一种可序列化的
iseralizable
-lite。您可以在网络程序中使用它,方法是拥有一个与开放式网络套接字连接对应的
对象,然后将其环绕在
EndianBinaryWriter | Reader
对象周围,并通过这些对象执行所有IO操作。作为奖励,您可以免费获得磁盘序列化:只需使用
文件流
而不是网络流。

您描述的方法实际上就是我打包数据的方式。我的问题涉及到更多,当我打包结构时,它是13个字节,正如我所期望的,但是当我读取它时,如果我尝试使用结构的大小来读取它(即Marshal.sizeOf(typeof(Type)),它返回16个字节,因为(根据我的假设)将字节对齐到16字节的效率。我只是问我是否应该使用我知道的类型大小读取数组,并在每次我通过更新某些值向结构添加更多数据时更改该大小。@DYamamoto对于序列化,最好为每个自描述的对象写一个头:它应该包括某种魔术字符串(用于标识对象类型),一个版本号,以及序列化对象的长度(以字节为单位)。然后从流中读回该值,并以此作为读取对象的基础。@DYamamoto我用一个检查和写入大小信息的示例修改了我的代码。您描述的方法实际上是我如何打包数据。我的问题涉及到更多内容当我打包结构时,它是13个字节,正如我所期望的,但是当我读取它时,如果我尝试使用结构的大小来读取它(即Marshal.sizeOf(typeof(Type)),它返回16个字节,因为(根据我的假设)将字节对齐到16字节的效率。我只是问我是否应该使用我知道的类型大小读取数组,并在每次我通过更新某些值向结构添加更多数据时更改该大小。@DYamamoto对于序列化,最好为每个自描述的对象写一个头:它应该包括某种神奇的字符串(用于标识对象类型)、版本号和序列化对象的长度(以字节为单位)。然后从流中读回该字符串,并将其用作读取对象的基础。@DYamamoto我用一个检查和写入大小信息的示例修改了代码。
struct Foo {
    public const  Int32 Size = sizeof(Byte) + (sizeof(Single) * 3);
    public Byte   B;
    public Single F1;
    public Single F2;
    public Single F3;

    public void Serialize(EndianBinaryWriter wtr) {
        wtr.Write( Size );
        wtr.Write( B );
        wtr.Write( F1 );
        wtr.Write( F2 );
        wtr.Write( F3 );
    }

    public static Foo Deserialize(EndianBinaryReader rdr) {
        if( rdr.ReadInt32() != Size ) throw new ...
        Foo f;
        f.B  = rdr.ReadByte();
        f.F1 = rdr.ReadSingle();
        f.F2 = rdr.ReadSingle();
        f.F3 = rdr.ReadSingle();
        return f;
    }
}