昨天把我的 Hubble.net 項目在x64下測試發現有異常,但在32位作業系統下沒有問題,抓狂!查了好幾個小時最後發現居然是 LayoutKind.Explicit 的問題,網上搜尋了半天,中英文的都看了,沒找到為什麼這個會造成.net 在不同平台上表現不一樣,不管怎麼樣,我還是把這個問題寫出來,大家看了以後可以避免犯同樣的錯誤。
.net 號稱是可以跨平台的,至少在 windows 平台下代碼是可以相互移植的,代碼的表現應該是一致的,這都是我想當然的結果,但昨天的這個問題打破了我美好的想象。問題是這樣的,如果你的代碼中有一個結構聲明為 LayoutKind.Explicit ,且這個結構中有參考型別欄位,那麼在 64位作業系統(我只測試了windows2003 x64)下將存在反射問題。具體看下面代碼:
[StructLayout(LayoutKind.Explicit)]
struct Struct1
{
[FieldOffset(0)]
public int FileIndex;
[FieldOffset(4)]
public string Data;
}
[StructLayout(LayoutKind.Explicit)]
struct Struct1
{
[FieldOffset(0)]
public int FileIndex;
[FieldOffset(4)]
public int[] Data;
}
[StructLayout(LayoutKind.Explicit)]
struct Struct1
{
[FieldOffset(0)]
public int FileIndex;
[FieldOffset(4)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)]
public int[] Data;
}
以上三個結構體是我用於測試的結構體,你的代碼中只要有其中一個或類似的結構體定義,那麼在 windows x64 下執行如下語句
System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly();
foreach (Type type in asm.GetTypes())
{
Console.WriteLine(type);
}
就會出現如下異常:
無法載入一個或多個請求的類型。有關更多資訊,請檢索 LoaderExceptions 屬性。 在 System.Reflection.Module._GetTypesInternal(StackCrawlMark& stackMark)
在 System.Reflection.Assembly.GetTypes()
但上述代碼在 windows 32 位作業系統下(測試了 XP 和 windows 2003 32bit) 運行完全沒有問題。我考慮會不會是編譯時間要指定平台為 x64 ,測試了一下,指定平台為 x64 後,在windows x64 下運行依然會產生上述異常。
但如果結構的定義為這樣,在x64 下則不會出現異常。
[StructLayout(LayoutKind.Explicit)]
struct Struct1
{
[FieldOffset(0)]
public int FileIndex;
[FieldOffset(4)]
public int Data;
}
總結:
為了保證我們的.net 程式的平台相容性,我們應盡量避免在採用 StructLayout(LayoutKind.Explicit) 屬性申明的結果體中定義參考型別欄位。至於為什麼32bit 和 64bit 下結果不一樣,我沒有找到相關資料,如果哪位大俠知道,望不吝賜教,謝謝!