Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Marshal.SizeOf throws ArgumentException on enums

Consider this code:

public enum MyEnum { V1, V2, V3 }  int size = Marshal.SizeOf(typeof(MyEnum)); 

it throws the exception:

An unhandled exception of type 'System.ArgumentException' occurred in TestConsole.exe

Additional information: Type 'TestConsole.Program+MyEnum' cannot be marshaled as an unmanaged structure; no meaningful size or offset can be computed.

While this code doesn't throw an exception and size contains 4:

public enum MyEnum { V1, V2, V3 }  public struct MyStruct {     public MyEnum en; }  int size = Marshal.SizeOf(typeof(MyStruct)); 

Can anyone explain why the .NET framework can't figure out that the enum is 4 bytes in the first sample code?

UPDATE

Marshal.Sizeof() failed on me in this generic method:

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

And the compiler didn't complain about enum not being a struct.

SOLUTION

I could refactor my generic method to make it work for both struct and 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); 
like image 861
huysentruitw Avatar asked Jul 26 '13 11:07

huysentruitw


1 Answers

This appears to be a limitation imposed by a difference between the requirements of ECMA-335 for enums (ECMA-335 Partition II §14.3):

...they shall have auto field layout (§10.1.2); ...

And the expectations of Marshal.SizeOf:

You can use this method when you do not have a structure. The layout must be sequential or explicit.

Based on this, you will need to use Enum.GetUnderlyingType before calling Marshal.SizeOf.

like image 176
Sam Harwell Avatar answered Sep 21 '22 04:09

Sam Harwell