使用结构数组和大小参数索引封送 C# 结构

Marshaling C# struct with array of structs and size param index

我已经阅读了几个主题,但我仍然无法理解无法轻松将此结构转换为字节数组的真正限制:

[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() 中总是有一些例外。

在此示例中,我收到以下错误:“[...] 无法作为非托管结构进行编组;无法计算有意义的大小或偏移量。”

结构初始化例如:

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

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

Marshal.SizeOf(a);

您无法像 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;
}