Преобразование любого объекта в байт []
Я пишу прототип 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();