it-swarm.com.de

Konvertieren Sie ein beliebiges Objekt in ein Byte [].

Ich schreibe eine Prototypverbindung TCP und habe Probleme, die zu sendenden Daten zu homogenisieren.

Im Moment sende ich nur Strings, aber in Zukunft möchten wir jedes Objekt versenden können. 

Der Code ist im Moment ziemlich einfach, weil ich dachte, dass alles in ein Byte-Array umgewandelt werden könnte:

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

Dies ist natürlich mit einem einfach genug gelöst 

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

Das Problem ist, wenn ich es auf diese Weise mache, muss ich nach JEDEM Objekttyp suchen, der zur Laufzeit nicht in ein Byte [] umgewandelt werden kann.

Da ich nicht jedes Objekt kenne, das zur Laufzeit nicht in ein Byte [] umgewandelt werden kann, ist dies wirklich keine Option.

Wie konvertiert man ein beliebiges Objekt in ein Byte-Array in C # .NET 4.0?

112
Steve H.

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

Beachten Sie, dass obj und alle Eigenschaften/Felder in obj (und so weiter für alle ihre Eigenschaften/Felder) alle mit dem Serializable-Attribut gekennzeichnet sein müssen, damit sie erfolgreich serialisiert werden.

164
Daniel DiPaolo

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

Verwenden Sie den folgenden 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;
}
89
kombsh

Wie andere schon gesagt haben, können Sie die binäre Serialisierung verwenden, aber es können zusätzliche Bytes erzeugt oder in Objekte mit nicht genau denselben Daten deserialisiert werden. Die Verwendung von Reflektionen dagegen ist ziemlich kompliziert und sehr langsam ... Es gibt eine andere Lösung, die Ihre Objekte strikt in Bytes und umgekehrt umwandeln kann - 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);

Und um Bytes in Objekt zu konvertieren:

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

Es ist merklich langsamer und zum Teil unsicher, diesen Ansatz für kleine Objekte und Strukturen im Vergleich zu Ihrem eigenen Serialisierungsfeld für Feld zu verwenden (wegen des doppelten Kopierens aus/in nicht verwalteten Speicher). Dies ist jedoch der einfachste Weg, um das Objekt streng in Byte [] umzuwandeln, ohne die Serialisierung zu implementieren und ohne [Serializable] -Attribut.

21
Aberro

Was Sie suchen, ist die Serialisierung. Für die .NET-Plattform stehen verschiedene Serialisierungsformen zur Verfügung

12
JaredPar
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;
    }
}

Sie können es wie im folgenden Code verwenden.

        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
Frank Myat Thu

Wie wäre es mit so etwas Einfachem?

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

Alternative Methode zum Konvertieren eines Objekts in ein Byte-Array:

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

Ich verwende lieber den Ausdruck "Serialisierung" als "Umwandlung in Bytes". Das Serialisieren eines Objekts bedeutet, dass es in ein Byte-Array (oder XML oder etwas anderes) konvertiert wird, das in der Remote-Box zur Rekonstruktion des Objekts verwendet werden kann. In .NET kennzeichnet das Attribut Serializable Typen, deren Objekte serialisiert werden können.

1
Matthias Meid

Sie können die eingebauten Serialisierungs-Tools im Framework verwenden und zu einem MemoryStream serialisieren. Dies ist möglicherweise die einfachste Option, kann jedoch ein größeres Byte [] erzeugen, als für Ihr Szenario unbedingt erforderlich ist.

Wenn dies der Fall ist, können Sie Reflection verwenden, um die Felder und/oder Eigenschaften des zu serialisierenden Objekts zu iterieren und sie manuell in den MemoryStream zu schreiben, wobei die Serialisierung rekursiv aufgerufen wird, wenn nicht triviale Typen serialisiert werden müssen. Diese Methode ist komplexer und benötigt mehr Zeit für die Implementierung. Sie bietet jedoch viel mehr Kontrolle über den serialisierten Stream.

1
Josh

Kombinierte Lösungen in Extensions-Klasse:

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
Error404

Die Verwendung von Encoding.UTF8.GetBytes ist schneller als die Verwendung von MemoryStram. Hier verwende ich NewtonsoftJson , um das Eingabeobjekt in eine JSON-Zeichenfolge zu konvertieren und dann Bytes von der JSON-Zeichenfolge zu erhalten. 

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

Benchmark für die Version von @Daniel DiPaolo mit dieser 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 |
0
kiran

Eine zusätzliche Implementierung, die Newtonsoft.Json binary JSON verwendet und nicht alle Elemente mit dem Attribut [Serializable] kennzeichnen muss. Der einzige Nachteil ist, dass ein Objekt in eine anonyme Klasse eingeschlossen werden muss. Daher kann das mit binärer Serialisierung erhaltene Byte-Array sich von diesem unterscheiden.

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

Die anonyme Klasse wird verwendet, weil BSON mit einer Klasse oder einem Array beginnen soll . Ich habe nicht versucht, Byte [] zurück zum Objekt zu deserialisieren und nicht sicher, ob es funktioniert, aber ich habe die Geschwindigkeit der Konvertierung in Byte [] und es vollständig getestet befriedigt meine Bedürfnisse.

0
prime_z