将任何对象转换为byte
我正在写一个原型的TCP连接,我有一些麻烦均匀化数据发送。
目前,我只发送string,但将来我们希望能够发送任何对象。
这个代码目前非常简单,因为我认为所有东西都可以被转换成一个字节数组:
void SendData(object headerObject, object bodyObject) { byte[] header = (byte[])headerObject; //strings at runtime, byte[] body = (byte[])bodyObject; //invalid cast exception // Unable to cast object of type 'System.String' to type 'System.Byte[]'. ... }
这当然很容易解决了
if( state.headerObject is System.String ){...}
问题是,如果我这样做,我需要检查在运行时无法转换为字节[]的每种types的对象。
由于我不知道在运行时无法将每个对象都转换为byte [],所以这不是一个选项。
如何将任何对象转换为C#.NET 4.0中的字节数组?
使用BinaryFormatter
:
byte[] ObjectToByteArray(object obj) { if(obj == null) return null; BinaryFormatter bf = new BinaryFormatter(); using (MemoryStream ms = new MemoryStream()) { bf.Serialize(ms, obj); return ms.ToArray(); } }
请注意obj
和obj
任何属性/字段(以及其所有属性/字段的其他属性/字段)都将需要使用Serializable
属性进行标记,以便与此Serializable
成功。
结帐这篇文章: http : //www.morgantechspace.com/2013/08/convert-object-to-byte-array-and-vice.html
使用下面的代码
// Convert an object to a byte array private byte[] ObjectToByteArray(Object obj) { if(obj == null) return null; BinaryFormatter bf = new BinaryFormatter(); MemoryStream ms = new MemoryStream(); bf.Serialize(ms, obj); return ms.ToArray(); } // Convert a byte array to an Object private Object ByteArrayToObject(byte[] arrBytes) { MemoryStream memStream = new MemoryStream(); BinaryFormatter binForm = new BinaryFormatter(); memStream.Write(arrBytes, 0, arrBytes.Length); memStream.Seek(0, SeekOrigin.Begin); Object obj = (Object) binForm.Deserialize(memStream); return obj; }
像其他人之前所说的那样,您可以使用二进制序列化,但可能会产生额外的字节或反序列化到具有不完全相同数据的对象。 另一方面使用reflection是相当复杂和非常缓慢的。 还有另一个解决scheme,可以严格地将您的对象转换为字节,反之亦然 – 编组:
var size = Marshal.SizeOf(your_object); // Both managed and unmanaged buffers required. var bytes = new byte[size]; var ptr = Marshal.AllocHGlobal(size); // Copy object byte-to-byte to unmanaged memory. Marshal.StructureToPtr(your_object, ptr, false); // Copy data from unmanaged memory to managed buffer. Marshal.Copy(ptr, bytes, 0, size); // Release unmanaged memory. Marshal.FreeHGlobal(ptr);
并将字节转换为对象:
var bytes = new byte[size]; var ptr = Marshal.AllocHGlobal(size); Marshal.Copy(bytes, 0, ptr, size); var your_object = (YourType)Marshal.PtrToStructure(ptr, typeof(YourType)); Marshal.FreeHGlobal(ptr);
对于小型对象和结构来说,使用这种方法显然比较慢,部分是不安全的(因为从/到非托pipe内存的双重拷贝),但是在不实现序列化的情况下严格地将对象转换为字节[]并且没有[Serializable]属性。
你正在寻找的是序列化。 .Net平台有几种可用的序列化forms
- 二进制序列化
- XML序列化:生成一个string,很容易转换为
byte[]
- ProtoBuffers
public static class SerializerDeserializerExtensions { public static byte[] Serializer(this object _object) { byte[] bytes; using (var _MemoryStream = new MemoryStream()) { IFormatter _BinaryFormatter = new BinaryFormatter(); _BinaryFormatter.Serialize(_MemoryStream, _object); bytes = _MemoryStream.ToArray(); } return bytes; } public static T Deserializer<T>(this byte[] _byteArray) { T ReturnValue; using (var _MemoryStream = new MemoryStream(_byteArray)) { IFormatter _BinaryFormatter = new BinaryFormatter(); ReturnValue = (T)_BinaryFormatter.Deserialize(_MemoryStream); } return ReturnValue; } }
你可以像下面的代码一样使用它。
DataTable _DataTable = new DataTable(); _DataTable.Columns.Add(new DataColumn("Col1")); _DataTable.Columns.Add(new DataColumn("Col2")); _DataTable.Columns.Add(new DataColumn("Col3")); for (int i = 0; i < 10; i++) { DataRow _DataRow = _DataTable.NewRow(); _DataRow["Col1"] = (i + 1) + "Column 1"; _DataRow["Col2"] = (i + 1) + "Column 2"; _DataRow["Col3"] = (i + 1) + "Column 3"; _DataTable.Rows.Add(_DataRow); } byte[] ByteArrayTest = _DataTable.Serializer(); DataTable dt = ByteArrayTest.Deserializer<DataTable>();
您可以使用框架中的内置序列化工具并序列化为MemoryStream 。 这可能是最直接的select,但可能会产生比您的scheme严格需要的更大的字节[]。
如果是这种情况,可以利用reflection来遍历要序列化的对象中的字段和/或属性,并手动将它们写入到MemoryStream中,如果需要序列化非平凡types,则recursion地调用序列化。 这种方法更复杂,需要更多的时间来实现,但是可以更多的控制序列化的stream。
将对象转换为字节数组的替代方法:
TypeConverter objConverter = TypeDescriptor.GetConverter(objMsg.GetType()); byte[] data = (byte[])objConverter.ConvertTo(objMsg, typeof(byte[]));
如何序列化? 看看这里 。
我宁愿使用expression式“序列化”比“铸成字节”。 序列化一个对象意味着把它转换成一个可以在远程盒子上使用的字节数组(或者其他的东西)来重新构造对象。 在.NET中, Serializable
属性标记可以序列化对象的types。
干杯,马提亚斯
一个额外的实现,它使用Newtonsoft.Json二进制JSON,并不需要用[Serializable]属性标记所有内容。 只有一个缺点是一个对象必须被包装在匿名类中,所以用二进制序列化获得的字节数组可能与这个不同。
public static byte[] ConvertToBytes(object obj) { using (var ms = new MemoryStream()) { using (var writer = new BsonWriter(ms)) { var serializer = new JsonSerializer(); serializer.Serialize(writer, new { Value = obj }); return ms.ToArray(); } } }
匿名类被使用,因为BSON应该从一个类或数组开始。 我还没有尝试反序列化byte []回到对象,不知道它是否工作,但已经testing了转换为byte []的速度,它完全满足我的需要。
在扩展类中的组合解决scheme:
public static class Extensions { public static byte[] ToByteArray(this object obj) { var size = Marshal.SizeOf(data); var bytes = new byte[size]; var ptr = Marshal.AllocHGlobal(size); Marshal.StructureToPtr(data, ptr, false); Marshal.Copy(ptr, bytes, 0, size); Marshal.FreeHGlobal(ptr); return bytes; } public static string Serialize(this object obj) { return JsonConvert.SerializeObject(obj); } }
这样简单的事情呢?
return ((object[])value).Cast<byte>().ToArray();