数週間前に関連する質問を投稿しました: 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に値を直接突っ込む必要があります。
では、クラス内でネストされたクラスの配列を定義する正しい方法は何ですか?