I work with a USB device, arrays of bytes with various data packets come from it. It is logical that you want to work with the package not as with an array of bytes, but as with a structure / class with meaningful fields.

In C ++, converting a byte array to a structure or class is very simple:

struct A { int param1; int param2; byte param3; } byte Packet[9]; //массив с пакетом, содержащим структуру А A* pA = (A*)(&Packet[0]); 

Is it possible in C # to convert a byte array to a structure / class in a similar way?

I really do not want for each package to write with hands the code that fills in the fields, like this:

  public class ProcessorId { public UInt32 Id0 { get; private set; } public UInt32 Id1 { get; private set; } public ProcessorId(byte[] data, int offset) { Id0 = BitConverter.ToUInt32(data.Skip(offset).Take(4).Reverse().ToArray(), 0); Id1 = BitConverter.ToUInt32(data.Skip(offset + 4).Take(4).Reverse().ToArray(), 0); } } 

If there are a couple dozen of parameters, this is so much useless work, which in C ++ is performed in a single line.

  • @yabloko then he and "managed" code, that frills with pointers, as it were, are not encouraged. :-) But you can write processing in C ++ and call and .net. How do you like this? - pvkovalev
  • one
    > Convert a byte array to a deserialization structure / class. - etki

1 answer 1

In C ++, converting a byte array to a structure or class is very simple:

It is very easy to shoot this leg in your own leg, because alignment and litte-big endianess must be taken into account. And if your percents can not read unaligned data, and you say anything anyway to this way, then your leg will tear off completely.

If you really want to, as in with ++, you can use the StructLayout Sequential and marshal

 public T ReadStruct<T> (Stream fs) { byte[] buffer = new byte[Marshal.SizeOf(typeof( T))]; fs.Read(buffer, 0, Marshal.SizeOf(typeof(T))); GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); T temp = (T) Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); handle.Free(); return temp; } 

With # -way (For Big-Enddian you need your own BinaryReader)

 public ProcessorId(BinaryReader br) { // где br это new BinaryReader(new MemoryStream(data)); Id0 = br.ReadUInt32(); Id1 = br.ReadUInt32(); } // используем var data = USB.Get(); var br = new BinaryReader(new MemoryStream(data)); var a1 = new ProcessorId(br); var a2 = new ProcessorId(br); var a3 = new ProcessorId(br); 
  • +1 for endianness and alignment. And for the right path, of course. - VladD
  • one
    Thank! The second option looks very elegant, which even no longer wants to get involved in marshaling. - yabloko