2013-07-26 14 views
43

Considerate questo codice:Marshal.SizeOf getta ArgumentException su enumerazioni

public enum MyEnum { V1, V2, V3 } 

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

si genera l'eccezione:

un'eccezione non gestita di tipo 'System.ArgumentException' si è verificato in TestConsole.exe

Ulteriori informazioni: digitare "TestConsole.Program + MyEnum" non può essere sottoposto a marshalling come una struttura non gestita; nessuna dimensione significativa o offset può essere calcolato .

Anche se questo codice non un'eccezione e size contiene 4:

public enum MyEnum { V1, V2, V3 } 

public struct MyStruct 
{ 
    public MyEnum en; 
} 

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

Qualcuno può spiegare perché il framework .NET non riesce a capire che il enum è di 4 byte nel primo campione codice?

UPDATE

Marshal.Sizeof() fallito su di me in questo metodo generico:

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

e il compilatore non si lamentava enum non essere un struct.

SOLUZIONE

potevo refactoring il mio metodo generico per farlo funzionare sia per struct e 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

[questo] (http://stackoverflow.com/questions/4219413/c-sharp-sizeofenum-alternative-to-workaro-resharper-false-error) non spiega il motivo, ma offre una soluzione alternativa. –

+0

Al contrario, è possibile creare un tipo di puntatore a 'MyEnum', con codice non sicuro, che usa il tipo' MyEnum * '. –

risposta

25

Questo sembra essere una limitazione imposta da una differenza tra le esigenze di ECMA-335 per enumerazioni (ECMA-335 Partizione II §14.3):

... devono avere una disposizione automatica del campo (§10.1.2); ...

E le aspettative di Marshal.SizeOf:

È possibile utilizzare questo metodo quando non si dispone di una struttura. Il layout deve essere sequenziale o esplicito.

In base a questo, è necessario utilizzare Enum.GetUnderlyingType prima di chiamare Marshal.SizeOf.

+0

Tutte le enumerazioni hanno un layout automatico, indipendentemente dal fatto che tu fornisca o meno il tipo sottostante. È una proprietà nei metadati del bytecode sottostante. –

+0

Si noti che il seguente codice è valido (anche al di fuori del contesto 'non sicuro') e fornisce il valore previsto:' const int s = sizeof (MyEnum); '. Quindi il compilatore C# utilizza volentieri la "larghezza" del tipo integrale sottostante e l'espressione è considerata una costante in fase di compilazione. –

+2

La risposta sopra è corroborata dal fatto che se dichiariamo una 'struct' con un paio di campi interi (diciamo) in essa e decoriamo la struct con l'attributo' [StructLayout (LayoutKind.Auto)] ', allora questa struct si comporta esattamente come un enum tipo wrt. "taglia di". Quello è "Marshal.SizeOf" genera la stessa eccezione, mentre 'sizeof (...)' funziona (ma è permesso solo nel contesto 'non sicuro 'dal momento che questa" dimensione "non è considerata una costante in fase di compilazione). –

0

Marshal.SizeOf(t) ha voglia di avere una struttura non gestito e un enum è una struct gestito . .NET può capire la dimensione costante di un'enumerazione:

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

@ 0699 - Probabilmente hai ragione ma hai un riferimento? –

+0

Per il caso speciale di un Enum potrebbe esserci il metodo [Enum.GetUnderlyingType] (http://msdn.microsoft.com/en-us/library/system.enum.getunderlyingtype.aspx) di interesse – metadings

+0

Copia il codice da Wouter Huysentruit e leggere l'eccezione 'Tipo' MyEnum 'non può essere eseguito il marshalling come una struttura non gestita; non è possibile calcolare dimensioni o offset significativi. ' – 0699

Problemi correlati