字节序列化C#中的结构的字节

我正在寻找C#中序列化的语言支持。 我可以从ISerializable派生并通过在字节缓冲区中复制成员值来实现序列化。 但是,我更喜欢像C / C ++那样的自动方式。

请考虑以下代码:

using System; using System.Text; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.IO; namespace XBeeHelper { class XBee { [Serializable()] public struct Frame where FrameType : struct { public Byte StartDelimiter; public UInt16 Lenght; public Byte APIIdentifier; public FrameType FrameData; public Byte Checksum; } [Serializable()] public struct ModemStatus { public Byte Status; } public Byte[] TestSerialization() { Frame frame = new Frame(); frame.StartDelimiter = 1; frame.Lenght = 2; frame.APIIdentifier = 3; frame.FrameData.Status = 4; frame.Checksum = 5; BinaryFormatter formatter = new BinaryFormatter(); MemoryStream stream = new MemoryStream(); formatter.Serialize(stream, frame); Byte[] buffer = stream.ToArray(); return buffer; } } } 

我有一个通用的Frame结构作为许多类型有效负载的包装器,用于串行传输。 ModemStatus是此类有效负载的示例。

但是,运行TestSerialization()会返回一个382字节长的缓冲区(没有预期的内容)! 它应该包含6个字节。 是否可以在不手动序列化的情况下正确序列化此数据?

只需使用以下两种方法:

 public static class StructTools { ///  /// converts byte[] to struct ///  public static T RawDeserialize(byte[] rawData, int position) { int rawsize = Marshal.SizeOf(typeof(T)); if (rawsize > rawData.Length - position) throw new ArgumentException("Not enough data to fill struct. Array length from position: "+(rawData.Length-position) + ", Struct length: "+rawsize); IntPtr buffer = Marshal.AllocHGlobal(rawsize); Marshal.Copy(rawData, position, buffer, rawsize); T retobj = (T)Marshal.PtrToStructure(buffer, typeof(T)); Marshal.FreeHGlobal(buffer); return retobj; } ///  /// converts a struct to byte[] ///  public static byte[] RawSerialize(object anything) { int rawSize = Marshal.SizeOf(anything); IntPtr buffer = Marshal.AllocHGlobal(rawSize); Marshal.StructureToPtr(anything, buffer, false); byte[] rawDatas = new byte[rawSize]; Marshal.Copy(buffer, rawDatas, 0, rawSize); Marshal.FreeHGlobal(buffer); return rawDatas; } } 

并指定你的结构(指定确切的大小和包(对齐)一个字节。默认为8):

 [StructLayout(LayoutKind.Explicit, Size = 11, Pack = 1)] private struct MyStructType { [FieldOffset(0)] public UInt16 Type; [FieldOffset(2)] public Byte DeviceNumber; [FieldOffset(3)] public UInt32 TableVersion; [FieldOffset(7)] public UInt32 SerialNumber; } 

现在您可以使用反序列化

 StructTools.RawDeserialize(byteArray, 0); // 0 is offset in byte[] 

和序列化使用

 StructTools.RawSerialize(myStruct); 

正如Chris所说 ,您可以使用不安全的代码 – 在这种情况下,您最好确保明确指定布局。 当然,你正在降低CLR的优化能力 – 你最终会得到不对齐的访问,失去primefaces性等等。这可能与你无关,但值得记住。

就个人而言,我认为这是一个非常脆弱的序列化/反序列化方式。 如果有任何变化,您的数据将无法读取。 如果您尝试在使用不同字节序的体系结构上运行,您将发现所有值都被搞砸了。此外,只要您需要使用引用类型,使用内存中布局就会失败 – 这很可能影响你自己的类型设计,鼓励你使用结构,否则你会使用类。

我更喜欢显式读取和写入值(例如,使用BinaryWriter,或者最好使用允许您设置字节序的二进制写入器版本 )或使用协议缓冲区等可移植序列化框架。

看到这个链接。 这使用Marshal机制来获取结构的actaul数据并将它们复制到Byte []。 另外,如何将它们复制回来。 关于这些函数的好处是它们是通用的,因此它将适用于所有结构(除非它们具有像字符串一样具有可变大小的数据类型)

http://dooba.net/2009/07/c-sharp-and-serializing-byte-arrays/

也许通用的Serialize / Deserialize方法:

 public static string SerializeObject(T obj) { string xmlString = null; using(MemoryStream memoryStream = new MemoryStream()) { using(XmlSerializer xs = new XmlSerializer(typeof(T))) { XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8); xs.Serialize(xmlTextWriter, obj); memoryStream = (MemoryStream)xmlTextWriter.BaseStream; xmlString = UTF8ByteArrayToString(memoryStream.ToArray()); } } return xmlString; } public static T DeserializeObject(string xml) { XmlSerializer xs = new XmlSerializer(typeof(T)); MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(xml)); XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8); return (T)xs.Deserialize(memoryStream); } 

原件在这里找到。