Маршалинг структуры C # с массивом структур и индексом параметров размера - PullRequest
0 голосов
/ 11 марта 2019

Я прочитал несколько тем, но до сих пор не могу понять реальное ограничение невозможности легко преобразовать эту структуру в байтовый массив:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct B {
  public int b_a;
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct A {
  public int sizeB;

  [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]
  public B[] b;
}

Я пишу коммуникационную программу TCP, поэтому я хочу собрать свои S2C-пакеты в структуру и затем отправить их в виде байта [], поэтому я ищу самый дешевый и быстрый способ достижения этого.

Я уже пробовал Marsheling во многих отношениях, но всегда есть некоторые исключения в Marshal.SizeOf ().

В этом примере я получаю следующую ошибку: «[...] нельзя маршалировать как неуправляемую структуру; невозможно вычислить значимый размер или смещение.»

Инициализация структуры, напр .::1010*

A a = new A();
B[] b = new B[5];

a.sizeB = 5;
a.b = b;

Marshal.SizeOf(a);

1 Ответ

0 голосов
/ 11 марта 2019

У вас нет такого же управления доступом к памяти низкого уровня, как у C или C ++. Вам нужно будет выполнить некоторую ручную работу, когда у вас есть массив неопределенной длины в C #.

Вот несколько способов сделать это.

struct B
{
    public int b_a;
}

struct A
{
    public int sizeB;

    public B[] b;
}

Первый - BinaryWriter. Это может быть быстрее, если в вашей структуре не много полей.

static byte[] ConvertToByte(A a)
{
    using (var ms = new MemoryStream())
    using (var writer = new BinaryWriter(ms))
    {
        writer.Write(a.sizeB);

        foreach (var b in a.b)
            writer.Write(b.b_a);

        return ms.ToArray();
    }
}

Другой - использовать маршаллинг, как вы, но явно перебирать массив.

static byte[] ConvertToByte(A a)
{
    var bStructSize = Marshal.SizeOf<B>();
    var size = bStructSize * a.b.Length;

    var arr = new byte[size + 4];

    var ptr = Marshal.AllocHGlobal(size);

    for (int i = 0; i < a.b.Length; i++)
        Marshal.StructureToPtr(a.b[i], ptr + i * bStructSize, true);

    Marshal.Copy(ptr, arr, 4, size);

    Array.Copy(BitConverter.GetBytes(a.sizeB), arr, 4);

    return arr;
}
...