[C#] 객체를 바이트로 변환 []

프로토 타입 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 ){...}

문제는 내가 그렇게하면 런타임에 byte []로 캐스팅 할 수없는 모든 유형의 객체를 확인해야한다는 것입니다.

런타임에 byte []로 캐스팅 할 수없는 모든 객체를 알지 못하기 때문에 이것은 실제로 옵션이 아닙니다.

C # .NET 4.0에서 객체를 바이트 배열로 어떻게 변환합니까?



답변

사용하십시오 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속성을 성공적으로 직렬화한다.


답변

이 기사를 확인하십시오 : 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;
}


답변

다른 사람들이 이전에 말했듯이 이진 직렬화를 사용할 수는 있지만 여분의 바이트를 생성하거나 정확히 동일한 데이터가 아닌 객체로 직렬화 해제 할 수 있습니다. 반면에 반사를 사용하는 것은 매우 복잡하고 매우 느립니다. 객체를 바이트로 변환하고 마샬링하는 다른 솔루션이 있습니다.

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

작은 객체에 대해이 접근 방식을 사용하는 것은 눈에 띄게 느리고 부분적으로 안전하지 않으며 (관리되지 않은 메모리에서 이중 복사로 인해 필드별로 자신의 직렬화와 비교하여) 직렬화를 구현하지 않고 객체를 바이트 []로 엄격하게 변환하는 가장 쉬운 방법입니다. 그리고 [직렬화 가능] 속성이 없습니다.


답변

당신이 찾고있는 것은 직렬화입니다. .Net 플랫폼에 사용 가능한 몇 가지 직렬화 형식이 있습니다.


답변

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


답변

을 사용하는 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 |


답변

확장 클래스의 결합 솔루션 :

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

}