Подтвердить что ты не робот

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 Framework не может понять, что 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.

Решение

Я мог бы реорганизовать мой общий метод, чтобы он работал как для struct, так и 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);
4b9b3361

Ответ 1

Это, по-видимому, ограничение, налагаемое разницей между требованиями ECMA-335 для перечислений (ECMA-335 Partition II, раздел 14.3):

... они должны иметь макет автоматического поля (§10.1.2);...

И ожидания Marshal.SizeOf:

Вы можете использовать этот метод, если у вас нет структуры. Макет должен быть последовательным или явным.

На основе этого вам нужно будет использовать Enum.GetUnderlyingType перед вызовом Marshal.SizeOf.

Ответ 2

Marshal.SizeOf(t) хочет иметь неуправляемую структуру, а enum - управляемая структура. .NET может определить постоянный размер перечисления:

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