2016-02-26 61 views
1

我试图映射C结构的C#与它的工作在一个包装类,但保持对结构运行到一个TypeLoadException,因为它:映射Ç联盟C#结构

包含对象场在偏移量2错误地对齐或被非对象字段重叠。

下面是相关的C代码:

#pragma pack(2) 

tyedef unsigned char SPECIAL_ID[16]; 

typedef struct _idType 
{ 
    unsigned char f; 
    unsigned char t; 
    union 
    { 
    unsigned short i_legacy; 
    SPECIAL_ID i; 
    } 
} IDTYPE; 

下面是在C#结构的最新尝试:

[StructLayout(LayoutKind.Explicit, Pack=2)] 
public struct IDTYPE 
{ 
    [FieldOffset(0)] 
    public System.Byte f; 
    [FieldOffset(1)] 
    public System.Byte t; 
    [FieldOffset(2)] 
    public ushort i_legacy; 
    [FieldOffset(2)] 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=16)] 
    public StringBuilder i; 
}; 

我曾尝试与不包= 2。我已经尝试将union移出到一个单独的结构,其显式布局和字段偏移量为0,然后在IDTYPE的布局顺序结构中使用该结构。我不太确定我要去哪里?

回答

3

对于联合使用类型总是最好的,然后将其与包含结构进行聚合。这可以让框架布置类型并计算偏移量,除了将所有成员放置在偏移零的工会之外。

联合中的字节数组使事情变得更加复杂。这里的一个选择是使用固定缓冲区。

[StructLayout(LayoutKind.Explicit)] 
public unsafe struct IDTYPE_UNION 
{ 
    [FieldOffset(0)] 
    public ushort i_legacy; 
    [FieldOffset(0)] 
    public fixed byte i[16]; 
}; 

把它放在含有结构是这样的:

[StructLayout(LayoutKind.Sequential, Pack=2)] 
public struct IDTYPE 
{ 
    public byte f; 
    public byte t; 
    public IDTYPE_UNION union; 
}; 

另一种选择是简单地忽略i_legacy会员,如果你真的需要读出的数据,从字节数组这样做:

[StructLayout(LayoutKind.Sequential, Pack=2)] 
public struct IDTYPE 
{ 
    public byte f; 
    public byte t; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=16)] 
    public byte[] i; 

    ushort i_legacy 
    { 
     get 
     { 
      return (ushort)((ushort)i[0] << 8 | (ushort)i[1]); 
     } 
    } 
}; 

此选项允许您避免使用不安全的代码。

+0

我真的很喜欢第二种选择,以避免不安全,但我有麻烦设置i_legacy的等价物。换句话说,我有一个2字节的数组(i_legacy的大小),我设置我相等,但我得到一个参数异常,因为数组编组不匹配结构的大小。我会如何在选项#2中设置“i_legacy”的等价物? – Tom

+1

只需将一个setter添加到指定给较大数组的索引0和1的属性即可。 –