Страницы

Поиск по вопросам

четверг, 13 февраля 2020 г.

Преобразование массива байт в структуру/класс

#c_sharp #массивы


Работаю с USB устройством, от него приходят массивы байт с различными пакетами данных.
Логично, что хочется работать с пакетом не как с массивом байт, а как со структурой/классом
с осмысленными полями.
В C++ преобразование байтового массива в структуру или класс делается очень просто:
struct A
{
  int param1;
  int param2;
  byte param3;
}

byte Packet[9]; //массив с пакетом, содержащим структуру А

A* pA = (A*)(&Packet[0]);

Можно ли в C# сделать преобразование массива байт в структуру/класс похожим образом? 
Очень не хочется для каждого пакета писать руками код, заполняющий поля, как тут:
 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);
    }
}

Если параметров будет пара десятков - это же столько бесполезной работы, которая
в С++ выполняется одной строчкой.    


Ответы

Ответ 1



В C++ преобразование байтового массива в структуру или класс делается очень просто: Очень просто прострелить этим кастом себе ногу, потому что надо учитывать выравнивание и litte-big endianess. А если ваш проц не может читать невыровненные данные, а вы скастуетесь абы куда таким образом, то ногу и вовсе оторвет. Если очень хочется как в с++, то можно использовать StructLayout Sequential и маршалить public T ReadStruct (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; } С#-way (Для Big-Enddian нужен свой 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);

Комментариев нет:

Отправить комментарий