Конвертировать любой объект в байт [] - PullRequest
119 голосов
/ 01 февраля 2011

Я пишу прототип 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 ){...}

Проблема в том, что если я делаю это таким образом, мне нужно проверять КАЖДЫЙ тип объекта, который не может быть приведен к байту [] во время выполнения.

Поскольку я не знаю каждый объект, который не может быть приведен к байту [] во время выполнения, это действительно не вариант.

Как преобразовать любой объект вообще в байтовый массив в C # .NET 4.0?

Ответы [ 13 ]

171 голосов
/ 01 февраля 2011

Используйте 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 , чтобы успешно сериализоваться с этим.

93 голосов
/ 13 августа 2013

оформить заказ в этой статье: 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;
}
23 голосов
/ 19 октября 2013

Как уже говорили другие, вы можете использовать двоичную сериализацию, но она может создать дополнительные байты или быть десериализована в объекты с не точно такими же данными.Использование отражения с другой стороны довольно сложно и очень медленно.Есть еще одно решение, которое может строго преобразовывать ваши объекты в байты и наоборот - маршаллинг:

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]атрибут.

12 голосов
/ 01 февраля 2011

То, что вы ищете, это сериализация.Для платформы .Net доступно несколько форм сериализации

7 голосов
/ 25 мая 2015
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>();
2 голосов
/ 31 октября 2018

Использование Encoding.UTF8.GetBytes быстрее, чем использование MemoryStram.Здесь я использую 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 |
2 голосов
/ 30 июля 2017

Комбинированные решения в классе расширений:

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

}
1 голос
/ 14 ноября 2017

Как насчет чего-то простого?

return ((object[])value).Cast<byte>().ToArray(); 
1 голос
/ 07 января 2014

Альтернативный способ преобразования объекта в байтовый массив:

    TypeConverter objConverter = TypeDescriptor.GetConverter(objMsg.GetType());
    byte[] data = (byte[])objConverter.ConvertTo(objMsg, typeof(byte[]));
1 голос
/ 01 февраля 2011

Вы можете использовать встроенные инструменты сериализации в платформе и сериализовать в MemoryStream .Это может быть самым простым вариантом, но может дать больший байт [], чем может быть строго необходимо для вашего сценария.

Если это так, вы можете использовать отражение для перебора полей и / или свойствв сериализуемом объекте и вручную запишите их в MemoryStream, рекурсивно вызывая сериализацию, если необходимо сериализовать нетривиальные типы.Этот метод является более сложным и займет больше времени для реализации, но позволяет вам гораздо больше контролировать сериализованный поток.

...