Search code examples
c#binaryformatter

Convert class object to byte[]


I'm writing a software in C# which has as input a generic class made by primitive types and should generate a bytestream. This bytestream must be sent to a PLC buffer.

I read so many articles here in StackOverflow which basically go in three solutions:

  1. Using binary formatter. This solution brings me a serializated binary stream (trying back Deserialize method returns me the original class) but checking the buffer I discovered that I can't find my data (see details below). Moreover I'm little bit worried by the fact that by checking Microsoft documentation the class is deprecated.

  2. Using binary writer. This works correctly, but having a lot of different class declarations I needs to use Reflections in order retrieve dinamically each type and serialize it and it sounds a little bit too complicated to me (I'm leaving it as a "plan b" solution).

  3. Using TypeDescriptor to convert the object. It doesn't work at all and Runtime engine returns "TypeConverter' is unable to convert X class"

  4. Binary formatter code try is as follows:

TYPE_S_TESTA test = new TYPE_S_TESTA();
test.b_tipo = 54;

using (MemoryStream ms = new MemoryStream())
{
    BinaryFormatter bf = new BinaryFormatter(); // BinaryFormatter is deprecated
    bf.Serialize(ms, test);
    ms.Seek(0, SeekOrigin.Begin);
    byte[] test3 = ms.ToArray();
}

Class to serialize is defined as follows:

    [Serializable]
    public class TYPE_S_TESTA
    {
        public short b_tipo;
        public char b_modo;
        public char b_area;
        public char b_sorgente;
        public char b_destinatario;
        public short w_lunghezza;
        public short w_contatore;
        public short w_turno;
        public short w_tempo;
    }

I already defined one value in my class as per test purposes. I expected a 14 bytes array with '54' inside (btw, another question is, what's the serialization order? I need exactly the same order as my definition). What I see with debugger on test3 buffer is instead:

_buffer {byte[512]} byte[]
        [0] 0   byte
        [1] 1   byte
        [2] 0   byte
        [3] 0   byte
        [4] 0   byte
        [5] 255 byte
        [6] 255 byte
        [7] 255 byte
        [8] 255 byte
        [9] 1   byte
        [10]    0   byte
        [11]    0   byte
        [12]    0   byte
        [13]    0   byte
        [14]    0   byte
        [15]    0   byte
        [16]    0   byte
        [17]    12  byte
        [18]    2   byte
        [19]    0   byte
        [20]    0   byte
        [21]    0   byte
        [22]    71  byte
        [23]    70  byte
        [24]    97  byte
        [25]    99  byte

So, no trace of my 54 and a 512 bytes buffer (why is it so big?).


Solution

  • You can declare TYPE_S_TESTA as follows:

    using System.Runtime.InteropServices
    
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct TYPE_S_TESTA
    {
        public short b_tipo;
        public char b_modo;
        public char b_area;
        public char b_sorgente;
        public char b_destinatario;
        public short w_lunghezza;
        public short w_contatore;
        public short w_turno;
        public short w_tempo;
    }
    

    You can convert an instance of a TYPE_S_TESTA to a byte array like this:

    TYPE_S_TESTA test = new TYPE_S_TESTA();
    test.b_tipo = 54;
    int size = Marshal.SizeOf(typeof(TYPE_S_TESTA));
    byte[] test3 = new byte[size];
    IntPtr ptr = Marshal.AllocHGlobal(size);
    Marshal.StructureToPtr(test, ptr, true);
    Marshal.Copy(ptr, test3, 0, size);