几周前我发布了一个相关问题: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中,这很难看,很容易出错,而且对未来的代码维护者来说也不清楚。
那么:在类中定义嵌套的类数组的正确方法是什么?
正如@GSerg所说,你应该使用structs。这些类还有其他相关的东西。我认为,正如他所说,编组指令导致了错误的尺寸。这里有一个更好的例子,将群组提取出来,这样会更令人反感。
[Serializable]
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct GROUP_T
{
public static GROUP_T Default = new GROUP_T() { ip_address = new byte[4] };
public ushort group;
public ushort line;
public ushort v_group;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.U1)]
public byte[] ip_address;
}
[Serializable]
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct LCT_T
{
public byte struct_version;
public ushort region_id;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] address;
}
public struct LCT_T_WITH_GROUP
{
public LCT_T lct;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 8)]
public GROUP_T[] groups;
}
class Program
{
static void Main(string[] _)
{
int sizeOfGroup = Marshal.SizeOf(typeof(GROUP_T));
int sizeOfStruct = Marshal.SizeOf(typeof(LCT_T));
int sizeOfLctWithGroup = Marshal.SizeOf(typeof(LCT_T_WITH_GROUP));
Console.WriteLine($"GROUP_T: {sizeOfGroup}");
Console.WriteLine($"LCT_T: {sizeOfStruct}");
Console.WriteLine($"LCT_T_WITH_GROUP: {sizeOfLctWithGroup}");
}
}
其输出为:组_T:10LCT_T:11LCT_WITH_GROUP:91