将任何对象转换为 byte[]

发布于 2024-10-15 02:10:57 字数 651 浏览 3 评论 0原文

我正在编写一个 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[]'.
  ...
}

这当然可以很容易地用 a 解决

if( state.headerObject is System.String ){...}

问题是,如果我这样做,我需要检查每种类型的对象不能在运行时转换为 byte[]。

由于我不知道每个不能在运行时转换为 byte[] 的对象,所以这确实不是一个选择。

在 C# .NET 4.0 中,如何将任何对象转换为字节数组?

I am writing a prototype TCP connection and I am having some trouble homogenizing the data to be sent.

At the moment, I am sending nothing but strings, but in the future we want to be able to send any object.

The code is quite simple at the moment, because I thought everything could be cast into a byte array:

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[]'.
  ...
}

This of course is easily enough solved with a

if( state.headerObject is System.String ){...}

The problem is, if I do it that way, I need to check for EVERY type of object that can't be cast to a byte[] at runtime.

Since I do not know every object that can't be cast into a byte[] at runtime, this really isn't an option.

How does one convert any object at all into a byte array in C# .NET 4.0?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

眼前雾蒙蒙 2024-10-22 02:10:57

使用 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 中的任何属性/字段(等等所有属性/字段)都需要标记为Serialized 属性 成功序列化。

Use the 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();
    }
}

Note that obj and any properties/fields within obj (and so-on for all of their properties/fields) will all need to be tagged with the Serializable attribute to successfully be serialized with this.

傲娇萝莉攻 2024-10-22 02:10:57

查看这篇文章: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;
}

checkout this article :http://www.morgantechspace.com/2013/08/convert-object-to-byte-array-and-vice.html

Use the below code

// 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;
}
楠木可依 2024-10-22 02:10:57

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

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[] 而不实现序列化且不使用 [Serialized] 属性的最简单方法。

Like others have said before, you could use binary serialization, but it may produce an extra bytes or be deserialized into an objects with not exactly same data. Using reflection on the other hand is quite complicated and very slow.
There is an another solution that can strictly convert your objects to bytes and vise-versa - marshalling:

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

And to convert bytes to object:

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

It's noticeably slower and partly unsafe to use this approach for small objects and structs comparing to your own serialization field by field (because of double copying from/to unmanaged memory), but it's easiest way to strictly convert object to byte[] without implementing serialization and without [Serializable] attribute.

作业与我同在 2024-10-22 02:10:57

使用 Encoding.UTF8.GetBytes 比使用 MemoryStream 更快。
在这里,我使用 NewtonsoftJson 将输入对象转换为 JSON 字符串,然后从 JSON 字符串获取字节。

byte[] SerializeObject(object value) =>Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value));

@Daniel DiPaolo 版本与此版本的基准

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 |

Using Encoding.UTF8.GetBytes is faster than using MemoryStream.
Here, I am using NewtonsoftJson to convert input object to JSON string and then getting bytes from JSON string.

byte[] SerializeObject(object value) =>Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value));

Benchmark for @Daniel DiPaolo's version with this version

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 |
神爱温柔 2024-10-22 02:10:57

您正在寻找的是序列化。 .Net 平台有多种可用的序列化形式

What you're looking for is serialization. There are several forms of serialization available for the .Net platform

蓝戈者 2024-10-22 02:10:57
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>();
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;
    }
}

You can use it like below code.

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>();
久随 2024-10-22 02:10:57

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

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

}

Combined Solutions in Extensions class:

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

}
ゞ记忆︶ㄣ 2024-10-22 02:10:57

像这样简单的事情怎么样?

return ((object[])value).Cast<byte>().ToArray(); 

How about something simple like this?

return ((object[])value).Cast<byte>().ToArray(); 
十年九夏 2024-10-22 02:10:57

您可以使用内置序列化工具 在框架中并序列化为 MemoryStream。这可能是最直接的选项,但可能会产生比您的场景严格需要的更大的 byte[]。

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

You could use the built-in serialization tools in the framework and serialize to a MemoryStream. This may be the most straightforward option, but might produce a larger byte[] than may be strictly necessary for your scenario.

If that is the case, you could utilize reflection to iterate over the fields and/or properties in the object to be serialized and manually write them to the MemoryStream, calling the serialization recursively if needed to serialize non-trivial types. This method is more complex and will take more time to implement, but allows you much more control over the serialized stream.

逆夏时光 2024-10-22 02:10:57

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

I'd rather use the expression "serialization" than "casting into bytes". Serializing an object means converting it into a byte array (or XML, or something else) that can be used on the remote box to re-construct the object. In .NET, the Serializable attribute marks types whose objects can be serialized.

北恋 2024-10-22 02:10:57

另一种实现使用 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[] 反序列化回对象,不确定它是否有效,但测试了转换为 byte[] 的速度,它完全满足我的需求。

One additional implementation, which uses Newtonsoft.Json binary JSON and does not require marking everything with the [Serializable] attribute. Only one drawback is that an object has to be wrapped in anonymous class, so byte array obtained with binary serialization can be different from this one.

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

Anonymous class is used because BSON should start with a class or array.
I have not tried to deserialize byte[] back to object and not sure if it works, but have tested the speed of conversion to byte[] and it completely satisfies my needs.

将军与妓 2024-10-22 02:10:57

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

TypeConverter objConverter = TypeDescriptor.GetConverter(objMsg.GetType());
byte[] data = (byte[])objConverter.ConvertTo(objMsg, typeof(byte[]));

Alternative way to convert object to byte array:

TypeConverter objConverter = TypeDescriptor.GetConverter(objMsg.GetType());
byte[] data = (byte[])objConverter.ConvertTo(objMsg, typeof(byte[]));
叹梦 2024-10-22 02:10:57
using System.Text.Json;

public static class MessageEncoder
{
    public static byte[] EncodeMessage<TObject>(this TObject message)
    {
         return JsonSerializer.SerializeToUtf8Bytes(message);
    }
}
using System.Text.Json;

public static class MessageEncoder
{
    public static byte[] EncodeMessage<TObject>(this TObject message)
    {
         return JsonSerializer.SerializeToUtf8Bytes(message);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文