Как взять коллекцию байтов и извлечь из нее типизированные значения? - PullRequest
0 голосов
/ 18 марта 2010

скажем, у меня есть коллекция байтов

var bytes = new byte[] {0, 1, 2, 3, 4, 5, 6, 7};

и я хочу извлечь определенное значение из байтов как управляемый тип, например ushort. Какой простой способ определить, какие типы находятся в каком месте в коллекции, и извлечь эти значения?

Один (безобразный) способ - использовать System.BitConverter и Queue или byte[] с индексом и просто выполнять итерацию, например ::

int index = 0;
ushort first = System.BitConverter.ToUint16(bytes, index);
index += 2; // size of a ushort
int second = System.BitConverter.ToInt32(bytes, index);
index += 4;
...

Этот метод становится очень, очень утомительным, когда вы имеете дело со многими из этих структур!

Я знаю, что есть System.Runtime.InteropServices.StructLayoutAttribute, который позволяет мне определять расположение типов внутри структуры или класса, но, похоже, нет способа импортировать коллекцию байтов в эту структуру. Если бы я мог как-то наложить структуру на коллекцию байтов и вытащить значения, это было бы идеально. Э.Г.

Foo foo = (Foo)bytes; // doesn't work because I'd need to implement the implicit operator
ushort first = foo.first;
int second = foo.second;
...
[StructLayout(LayoutKind.Explicit, Size=FOO_SIZE)]
public struct Foo  {
    [FieldOffset(0)] public ushort first;
    [FieldOffset(2)] public int second;
}

Есть мысли о том, как этого добиться?

[РЕДАКТИРОВАТЬ: См. Также мой вопрос о том, как обращаться с байтами, когда они старшего порядка .]

Ответы [ 2 ]

1 голос
/ 18 марта 2010

Мы сделали это совсем немного, поскольку общаемся напрямую с аппаратным обеспечением через байты через последовательный порт.

Учитывая определение структуры

[StructLayout(LayoutKind.Explicit, Size=FOO_SIZE)]
public struct Foo  {
    [FieldOffset(0)] public ushort first;
    [FieldOffset(2)] public int second;
}

Вы можете использовать такой класс, чтобы выполнить преобразование

public class ByteArrayToStruct<StructType>
{
    public StructType ConvertToStruct(int size, byte[] thebuffer)
    {
        try
        {
            int theSize = size;
            IntPtr ptr1 = Marshal.AllocHGlobal(theSize);
            Marshal.Copy(thebuffer, 0, ptr1, theSize);
            StructType theStruct = (StructType)Marshal.PtrToStructure(ptr1, typeof(StructType));
            Marshal.FreeHGlobal(ptr1);
            return theStruct;
        }
        catch (Exception)
        {
            return default(StructType);
        }
    }
}

И наоборот, вы можете также создать List из массива и сделать что-то вроде следующего:

ushort first = BitConverter.ToInt16(myList.ToArray(), 0);
myList.RemoveRange(0, sizeof(ushort));
[...]

Это, по сути, будет хранить соответствующие данные в «заголовке» списка, поэтому вам не нужно отслеживать положение в массиве.

0 голосов
/ 18 марта 2010

сделай это первым способом. определить класс Buffer, который имеет байты данных и курсор. Затем определяем такие методы, как getInt16, getInt32 и т. Д. Затем вы идете

  Buffer b(bytes);
  ushort a = b.getInt16();
  int x = b.getInt32();

У меня есть это в моей сумке утиля. У меня также есть противоположность, чтобы сделать буфер из строк ints, ....

...