Marshal.SizeOf throws ArgumentException on enums

huysentruitw picture huysentruitw · Jul 26, 2013 · Viewed 11k times · Source

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

Answer

Sam Harwell picture Sam Harwell · Jul 26, 2013

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.