Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/291.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将任何对象转换为字节[]_C#_.net_Object_Byte - Fatal编程技术网

C# 将任何对象转换为字节[]

C# 将任何对象转换为字节[],c#,.net,object,byte,C#,.net,Object,Byte,我正在编写一个原型TCP连接,在均匀化要发送的数据时遇到了一些问题 目前,我只发送字符串,但将来我们希望能够发送任何对象 代码目前非常简单,因为我认为所有内容都可以转换为字节数组: void SendData(object headerObject, object bodyObject) { byte[] header = (byte[])headerObject; //strings at runtime, byte[] body = (byte[])bodyObject;

我正在编写一个原型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中,如何将任何对象转换为字节数组?

使用:


请注意,
obj
obj
中的任何属性/字段(以及其所有属性/字段的其他属性/字段)都需要使用标记才能成功地进行序列化。

您要查找的是序列化。有几种形式的序列化可用于.Net平台

  • XML序列化:生成易于转换为
    字节[]的字符串。

我宁愿使用“序列化”而不是“转换为字节”。序列化对象意味着将其转换为字节数组(或XML或其他内容),可在远程框上用于重新构造对象。在.NET中,标记其对象可以序列化的类型。

您可以在框架中使用并序列化为。这可能是最简单的选择,但可能会产生比您的场景严格需要的更大的字节[]

如果是这种情况,您可以利用反射对要序列化的对象中的字段和/或属性进行迭代,并手动将它们写入MemoryStream,如果需要序列化非平凡类型,则递归调用序列化。此方法更复杂,需要花费更多的时间来实现,但允许您对序列化流进行更多的控制。

查看本文:

使用下面的代码

// 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;
}

正如其他人之前所说,您可以使用二进制序列化,但它可能会产生额外的字节,或者被反序列化为具有不完全相同数据的对象。另一方面,使用反射是非常复杂和缓慢的。 还有一种解决方案可以严格地将对象转换为字节,反之亦然—编组:

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);

与您自己的逐字段序列化相比,对小对象和结构使用这种方法显然要慢得多,而且部分不安全(因为从/到非托管内存进行了双重复制),但这是在不实现序列化和不使用[Serializable]的情况下将对象严格转换为字节[]的最简单方法属性。

将对象转换为字节数组的替代方法:

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[]'.
  ...
}
TypeConverter-objConverter=TypeDescriptor.GetConverter(objMsg.GetType());
byte[]data=(byte[])objConverter.ConvertTo(objMsg,typeof(byte[]);
公共静态类序列化
{
公共静态字节[]序列化程序(此对象_对象)
{   
字节[]字节;
使用(var _MemoryStream=new MemoryStream())
{
IFormatter_BinaryFormatter=新的BinaryFormatter();
_序列化(_MemoryStream,_object);
字节=_MemoryStream.ToArray();
}
返回字节;
}
公共静态T反序列化器(此字节[]\u字节数组)
{   
T返回值;
使用(var _MemoryStream=新的MemoryStream(_byteArray))
{
IFormatter_BinaryFormatter=新的BinaryFormatter();
ReturnValue=(T)_BinaryFormatter.反序列化(_MemoryStream);
}
返回值;
}
}
您可以像下面的代码一样使用它

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>();
DataTable\u DataTable=newdatatable();
_DataTable.Columns.Add(新数据列(“Col1”));
_DataTable.Columns.Add(新的DataColumn(“Col2”));
_DataTable.Columns.Add(新的DataColumn(“Col3”));
对于(int i=0;i<10;i++){
DataRow _DataRow=_DataTable.NewRow();
_数据行[“Col1”]=(i+1)+“第1列”;
_数据行[“Col2”]=(i+1)+“第2列”;
_数据行[“Col3”]=(i+1)+“第3列”;
_DataTable.Rows.Add(_DataRow);
}
字节[]ByteArrayTest=_DataTable.Serializer();
DataTable dt=ByteArrayTest.Deserializer();

另一个实现,它使用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应该以类或数组开头。
我没有尝试将字节[]反序列化回对象,也不确定它是否有效,但测试了转换为字节[]的速度,它完全满足了我的需要。

扩展类中的组合解决方案:

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(); 
返回((object[])值.Cast().ToArray();

使用
编码.UTF8.GetBytes
比使用
内存流
更快。 这里,我使用NewtonsoftJson将输入对象转换为JSON字符串,然后从JSON字符串中获取字节

byte[] SerializeObject(object value) =>Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value));
使用此版本的@Daniel DiPaolo版本的基准
这在一般意义上是不可能的(例如,考虑
FileStream
的一个实例,或者任何封装这样一个句柄的对象)。是否希望所有客户端都运行.NET?如果答案是“否”,则应该考虑其他形式的序列化(XML、JSON或类似的),小心对待另一边的“任何”对象,因为它可能不再有意义(例如,如果该对象是文件的句柄,或类似的)YUP,则应用正常的警告,但提醒它们的人并不是一个坏主意。
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 |