2013-07-26 12 views
43

diesen Code vor:Marshal.SizeOf wirft Argument auf Aufzählungen

Eine nicht behandelte Ausnahme des Typs 'System.ArgumentException' aufgetreten in TestConsole.exe

:

public enum MyEnum { V1, V2, V3 } 

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

es die Ausnahme auslöst

Weitere Informationen: Typ 'TestConsole.Program + MyEnum' kann nicht Marshalled als eine nicht verwaltete Struktur sein; keine sinnvolle Größe oder Versatz kann berechnet werden.

Während dieser Code nicht eine Ausnahme und size enthalten 4 wirft:

public enum MyEnum { V1, V2, V3 } 

public struct MyStruct 
{ 
    public MyEnum en; 
} 

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

jemand erklären kann, warum kann der .NET-Framework nicht herausfinden, dass die enum 4 Byte in der ersten Probe Code?

UPDATE

Marshal.Sizeof() scheiterte auf mich in dieser generischen Methode:

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); 
    } 
} 

Und der Compiler beschwerte sich nicht über enum keine struct zu sein.

SOLUTION

ich meine generische Methode Refactoring könnte es sowohl funktioniert für struct und enum:

// 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) erklärt nicht, warum, aber gibt einen Workaround. –

+0

Im Gegensatz dazu ist es möglich, einen Zeigertyp für 'MyEnum' zu erstellen, mit unsicherem Code, der den Typ' MyEnum * 'verwendet. –

Antwort

25

Dies scheint eine Beschränkung auferlegt durch eine Differenz zwischen den Anforderungen der ECMA-335 für Aufzählungen (ECMA-335 Partition §14.3 II) zu:

... müssen sie ein automatisches Feldlayout haben (§10.1.2); ...

und die Erwartungen der Marshal.SizeOf:

Sie können diese Methode verwenden, wenn Sie nicht über eine Struktur haben. Das Layout muss sequenziell oder explizit sein.

Darauf basierend müssen Sie Enum.GetUnderlyingType vor dem Aufruf Marshal.SizeOf verwenden.

+0

Alle Enums haben ein automatisches Layout, unabhängig davon, ob Sie den zugrunde liegenden Typ explizit angeben oder nicht. Es ist eine Eigenschaft in den zugrunde liegenden Bytecode-Metadaten. –

+0

Beachten Sie, dass der folgende Code (auch außerhalb des "unsicheren" Kontexts) gültig ist und den erwarteten Wert gibt: 'const int s = sizeof (MyEnum);'. Daher verwendet der C# -Compiler gerne die "Breite" des zugrunde liegenden Integraltyps, und der Ausdruck wird als Kompilierzeitkonstante betrachtet. –

+2

Die obige Antwort wird durch die Tatsache bestätigt, dass, wenn wir eine "struct" mit ein paar ganzzahligen Feldern (sagen wir) deklarieren und die Struktur mit dem Attribut "[StructLayout (LayoutKind.Auto)]" dekorieren, dann verhält sich diese Struktur genau wie ein enum type wrt. "Größe von". Das ist "Marshal.SizeOf" löst dieselbe Ausnahme aus, während "sizeof (...)' funktioniert (aber nur in 'unsicheren' Kontext erlaubt ist, da diese" Größe "nicht als Kompilierzeitkonstante betrachtet wird). –

0

Marshal.SizeOf(t) eine nicht verwaltete Struktur haben will, und eine Enumeration ist eine verwaltete Struktur . .NET kann die konstante Größe eines ENUM herauszufinden:

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

@ 0699 - Sie haben wahrscheinlich Recht, aber haben Sie eine Referenz? –

+0

Für den speziellen Fall einer Enum kann die Methode [Enum.GetUnderlyingType] (http://msdn.microsoft.com/en-us/library/system.enum.getunderlingtyp.aspx) von Interesse sein – metadings

+0

Kopieren Sie den Code aus Wouter Huysentruit und lesen Sie die Ausnahme 'Typ' MyEnum 'kann nicht als eine nicht verwaltete Struktur gemarshallt werden; es kann keine sinnvolle Größe oder kein Offset berechnet werden. – 0699