我正在编写一个原型TCP连接,我在整理要发送的数据时遇到了一些麻烦。
目前,我只发送字符串,但将来我们希望能够发送任何对象。
目前代码非常简单,因为我认为所有内容都可以转换为字节数组:
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 ){...}
问题是,如果我这样做,我需要检查在运行时无法转换为byte []的每种类型的对象。
由于我不知道在运行时无法将每个对象强制转换为byte [],因此这不是一个选项。
如何将任何对象转换为C#.NET 4.0中的字节数组?
答案 0 :(得分:169)
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
attribute进行标记才能成功用这个序列化。
答案 1 :(得分:92)
结帐这篇文章: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;
}
答案 2 :(得分:23)
与其他人之前所说的一样,您可以使用二进制序列化,但它可能会产生额外的字节或被反序列化为具有不完全相同数据的对象。另一方面,使用反射非常复杂且非常慢。 还有另一种解决方案可以严格地将对象转换为字节,反之亦然 - 编组:
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);
对于小对象和结构,使用这种方法比你自己的逐字段序列化(因为从/向非托管内存的双重复制)明显更慢和部分不安全,但它是将对象严格转换为byte []的最简单方法没有实现序列化和没有[Serializable]属性。
答案 3 :(得分:12)
您正在寻找的是序列化。 .Net平台有几种可用的序列化形式
byte[]
答案 4 :(得分:7)
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>();
答案 5 :(得分:2)
扩展中的组合解决方案类:
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);
}
}
答案 6 :(得分:1)
我宁愿使用表达式“serialization”而不是“cast into bytes”。序列化对象意味着将其转换为可以在远程框上重新构造对象的字节数组(或XML或其他)。在.NET中,Serializable
attribute标记其对象可以序列化的类型。
答案 7 :(得分:1)
您可以在框架中使用built-in serialization tools并序列化为MemoryStream。这可能是最直接的选项,但可能产生比您的场景严格必需的更大的byte []。
如果是这种情况,您可以利用反射来迭代要序列化的对象中的字段和/或属性,并手动将它们写入MemoryStream,如果需要序列化非平凡类型,则递归调用序列化。此方法更复杂,需要更多时间来实现,但允许您对序列化流进行更多控制。
答案 8 :(得分:1)
将对象转换为字节数组的替代方法:
TypeConverter objConverter = TypeDescriptor.GetConverter(objMsg.GetType());
byte[] data = (byte[])objConverter.ConvertTo(objMsg, typeof(byte[]));
答案 9 :(得分:1)
这样简单的事情怎么样?
return ((object[])value).Cast<byte>().ToArray();
答案 10 :(得分:1)
使用Encoding.UTF8.GetBytes
比使用MemoryStram
更快。
在这里,我正在使用 NewtonsoftJson 将输入对象转换为JSON字符串,然后从JSON字符串获取字节。
byte[] SerializeObject(object value) =>Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value));
Method | Mean | Error | StdDev | Median | Gen 0 | Allocated |
-------------------------- |---------:|----------:|----------:|---------:|-------:|--
ObjectToByteArray | 4.983 us | 0.1183 us | 0.2622 us | 4.887 us | 0.9460 | 3.9 KB |
ObjectToByteArrayWithJson | 1.548 us | 0.0309 us | 0.0690 us | 1.528 us | 0.3090 | 1.27 KB |
答案 11 :(得分:-1)
序列化怎么样?看看here。