几周前我发布了一个相关问题:Marshal.Sizeof() 返回意外值
作为背景,我们聘请了第三方将旧的 C++ 项目转换为 C#。这是一个通过以太网发送/接收消息的通信协议应用程序,其中所有消息都包含有效负载,这些有效负载是已定义结构的序列化表示:
typedef struct // size=10
{
ushort group;
ushort line;
ushort v_group;
byte ip_address[4];
}GROUP_T;
typedef struct // size=91
{
byte struct_version;
ushort region_id;
byte address[8];
GROUP_T groups[8];
} LCT_T;
这些被转换为 C# 类:
[Serializable]
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class GROUP_T
{
public ushort group;
public ushort line;
public ushort v_group;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.U1)]
public byte[] ip_address = new byte[4];
}
[Serializable]
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class LCT_T
{
public byte struct_version;
public ushort region_id;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] address = new byte[8];
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 80)]
public byte[] group_config_bytes = new byte[80];
}
我的问题是 LCT_T 类的 group_config_bytes 元素。以编程方式这是可行的,但是 GROUP_T 结构的原始数组丢失了等效的字节数组(最初,GROUP_T 数组为空且未使用)。现在我需要为单个 GROUP_T 对象设置值,所以我需要嵌套数组的类版本:
[Serializable]
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class LCT_T
{
public byte struct_version;
public ushort region_id;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] address = new byte[8];
[MarshalAs(UnmanagedType.ByValArray, ArraySubType=UnmanagedType.Struct,SizeConst = 10)]
public GROUP_T[] groups = new GROUP_T[8];
}
这可以编译,但 Marshal.SizeOf(typeof(LCT_T)) 返回错误的大小(应该是 11 + (8 * 10) = 91)。
如果没有这个更新的 LCT_T 类定义,如果我需要设置单个组的元素,我必须直接将值插入group_config_bytes,这很丑陋,容易出错,并且对于此代码的未来维护者来说不清楚。
那么:在类中定义嵌套类数组的正确方法是什么?