2013-07-26 48 views
43

考慮以下代碼:Marshal.SizeOf引發的ArgumentException上枚舉

public enum MyEnum { V1, V2, V3 } 

int size = Marshal.SizeOf(typeof(MyEnum)); 

它拋出異常:

類型 'System.ArgumentException' 未處理的異常發生在 TestConsole.exe

附加信息:類型'TestConsole.Program + MyEnum'不能作爲非託管結構編組爲 ;沒有有意義的大小或偏移可以計算出 。

儘管此代碼不拋出一個異常size包含4:

public enum MyEnum { V1, V2, V3 } 

public struct MyStruct 
{ 
    public MyEnum en; 
} 

int size = Marshal.SizeOf(typeof(MyStruct)); 

任何人都可以解釋爲什麼.NET框架想不通的是,enum是第一個樣品中4個字節碼?

UPDATE

Marshal.Sizeof()在這個通用方法失敗對我道:

public bool IoControlReadExact<T>(uint ioControlCode, out T output) where T : struct 
{ 
    output = new T(); 

    int outBufferSize = Marshal.SizeOf(typeof(T)); 
    IntPtr outBuffer = Marshal.AllocHGlobal(outBufferSize); 
    if (outBuffer == IntPtr.Zero) 
     return false; 
    try 
    { 
     uint bytesReturned; 
     return IoControlRead(ioControlCode, outBuffer, (uint)outBufferSize, out bytesReturned) && ((uint)outBufferSize == bytesReturned); 
    } 
    finally 
    { 
     output = (T)Marshal.PtrToStructure(outBuffer, typeof(T)); 
     Marshal.FreeHGlobal(outBuffer); 
    } 
} 

,編譯器並沒有抱怨enum不是一個struct

SOLUTION

我可以修改我的泛型方法,使之成爲既structenum工作:

// determine the correct output type: 
Type outputType = typeof(T).IsEnum ? Enum.GetUnderlyingType(typeof(T)) : typeof(T); 
//... 
int outBufferSize = Marshal.SizeOf(outputType); 
//... 
output = (T)Marshal.PtrToStructure(outBuffer, outputType); 
+2

[this](http://stackoverflow.com/questions/4219413/c-sharp-sizeofenum-alternative-to-workaround-resharper-false-error)不能解釋原因,但提供了一種解決方法。 –

+0

與此相反,它可以創建一個指向MyEnum的指針類型,並使用類型爲MyEnum *的不安全代碼。 –

回答

25

這似乎是限制由ECMA-335的要求之間,用於枚舉(ECMA-335分區Ⅱ§14.3)差施加:

...他們應該有自動場佈局(§10.1.2); ...

Marshal.SizeOf期望:

您可以使用此方法時,你沒有的結構。佈局必須是順序的或明確的。

基於此,您需要在致電Marshal.SizeOf之前使用Enum.GetUnderlyingType

+0

所有枚舉都具有自動佈局,無論您是否明確地給出基礎類型。它是底層字節碼元數據中的一個屬性。 –

+0

請注意,以下代碼是有效的(即使在不安全的上下文之外),並給出期望的值:const int s = sizeof(MyEnum);'。所以C#編譯器很樂意使用底層整型的「寬度」,表達式被認爲是編譯時常量。 –

+2

上面的回答可以通過以下事實來證實:如果我們聲明一個帶有幾個整型字段(比如說)的結構體,並用'[StructLayout(LayoutKind.Auto)]'屬性來修飾結構體,那麼這個結構體的行爲完全像一個枚舉型wrt。 「大小」。那就是'Marshal.SizeOf'拋出同樣的異常,而'sizeof(...)'工作(但是隻允許在'unsafe'上下文中,因爲這個「size」不被認爲是編譯時常量)。 –

0

Marshal.SizeOf(t)不希望有一個非託管結構和枚舉是一個管理結構。 .NET可以計算出一個枚舉的恆定大小:

int size1 = sizeof(MyEnum); 
Console.WriteLine("Enum: {0}", size1); 
int size2 = Marshal.SizeOf(typeof(MyStruct)); 
Console.WriteLine("Struct: {0}", size2); 
+2

@ 0699 - 你可能是對的,但你有參考嗎? –

+0

對於Enum的特殊情況,可能有[Enum.GetUnderlyingType](http://msdn.microsoft.com/en-us/library/system.enum.getunderlyingtype.aspx)感興趣的方法 – metadings

+0

複製代碼Wouter Huysentruit並且閱讀了異常'類型'MyEnum'不能作爲非託管結構編組;沒有意義的大小或偏移量可以計算出來。' – 0699