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