Преобразование любого объекта в байт []

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

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

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

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

Ответ 1

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

Ответ 2

checkout this article: 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;
}

Ответ 3

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

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].

Ответ 4

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

Ответ 5

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

Ответ 6

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

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

Ответ 7

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

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

Ответ 8

Как насчет сериализации? посмотрите здесь.

Ответ 9

Я предпочел бы использовать выражение "сериализация", чем "casting into bytes". Сериализация объекта означает преобразование его в массив байтов (или XML или что-то еще), которые можно использовать в удаленном поле для повторной конструирования объекта. В .NET атрибут Serializable указывает метки типов, объекты которых могут быть сериализованы.

Cheers, Matthias

Ответ 10

Одна дополнительная реализация, которая использует 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 должен начинаться с класса или массива. Я не пытался десериализовать байт [] назад на объект и не уверен, работает ли он, но проверял скорость преобразования в байт [], и он полностью удовлетворяет мои потребности.

Ответ 11

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

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

}

Ответ 12

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

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