2016-02-26 100 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的屬性即可。 –