web-dev-qa-db-fra.com

Marshal.SizeOf lance ArgumentException sur les énumérations

Considérez ce code:

public enum MyEnum { V1, V2, V3 }

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

il lève l'exception:

Une exception non gérée de type "System.ArgumentException" s'est produite dans TestConsole.exe

Informations supplémentaires: Le type "TestConsole.Program + MyEnum" ne peut pas être marshalé en tant que structure non gérée; aucune taille ou décalage significatif ne peut être calculé.

Bien que ce code ne lève pas d'exception et que size en contienne 4:

public enum MyEnum { V1, V2, V3 }

public struct MyStruct
{
    public MyEnum en;
}

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

Quelqu'un peut-il expliquer pourquoi le framework .NET ne peut pas comprendre que enum est de 4 octets dans le premier exemple de code?

MISE À JOUR

Marshal.Sizeof() a échoué sur moi dans cette méthode générique:

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

Et le compilateur ne s'est pas plaint du fait que enum n'était pas un struct.

SOLUTION

Je pourrais refactoriser ma méthode générique pour qu'elle fonctionne à la fois pour struct et 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);
45
huysentruitw

Cela semble être une limitation imposée par une différence entre les exigences de l'ECMA-335 pour les énumérations (ECMA-335 Partition II §14.3):

... ils doivent avoir une disposition de champ automatique (§10.1.2); ...

Et les attentes de Marshal.SizeOf:

Vous pouvez utiliser cette méthode lorsque vous n'avez pas de structure. La mise en page doit être séquentielle ou explicite.

Sur cette base, vous devrez utiliser Enum.GetUnderlyingType avant d'appeler Marshal.SizeOf.

26
Sam Harwell

Marshal.SizeOf(t) veut avoir une structure non managée, et une énumération est une structure gérée. . NET peut déterminer la taille constante d'une énumération:

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