我有一个看起来像这样的简单对象:
public class Foo
{
public UInt32 One { get; set; }
public UInt32 Two { get; set; }
public UInt32 Three { get; set; }
public UInt32 Four { get; set; }
}
我尝试了在网上某处找到的以下代码:
public byte[] ObjectToByteArray(Object obj)
{
MemoryStream fs = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(fs, obj);
byte[] rval = fs.ToArray();
fs.Close();
return rval;
}
但是以某种方式返回的字节数组的大小为248个字节。
我希望它是4个字节x 4个字段= 16个字节。
问题:
将固定对象转换为字节数组的最干净方法是什么?
在这种情况下,结果数组的大小应为16个字节吗?
BinaryFormatter保存了大量类型信息以能够正确反序列化。如果要紧凑的序列化或通过某种严格的协议进行通信,则必须像下面这样显式地进行:
public byte[] ToByteArray()
{
List<byte> result = new List<byte>();
result.AddRange(BitConverter.GetBytes(One));
result.AddRange(BitConverter.GetBytes(Two));
result.AddRange(BitConverter.GetBytes(Three));
result.AddRange(BitConverter.GetBytes(Four));
return result.ToArray();
}
在这里,我将每个UInt32转换为字节数组,并将其存储在结果数组中。
编辑
事实证明,还有另一种使用的方法struct
,Marshal
首先struct
使用以下属性进行制作和标记:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct MyStruct
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
public string StringField;
public int IntField;
}
此处LayoutKind.Sequential
告诉clr以与声明相同的顺序将字段保留在内存中。没有Pack = 1
结构会占用比所需更多的内存。就像struct
一个short
字段一样,一个字段byte
仅需要3个字节,但是默认情况下,它的大小很可能是4(处理器具有用于处理单个字节,2个字节和4个字节的指令,clr为每个struct实例牺牲一个字节以减少指令的数量)机器代码的一半)。现在您可以Marshal
用来复制字节:
public static byte[] GetBytes<T>(T str)
{
int size = Marshal.SizeOf(str);
var bytes = new byte[size];
IntPtr ptr = Marshal.AllocHGlobal(size);
try
{
Marshal.StructureToPtr(str, ptr, true);
Marshal.Copy(ptr, bytes, 0, size);
return bytes;
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
使用简单类型,一切都可以正常工作。对于复杂的类型,例如,string
您必须使用MarshalAs
attribute,并且使用它要复杂一些(例如,我告诉clr将字符串编组为固定的50个字节大小的数组)。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句