45 votes

Pourquoi Marshal.SizeOf lance-t-il ArgumentException sur des énumérations?

Considérons cet exemple de code:

public enum MyEnum { V1, V2, V3 }

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

il lève l'exception:

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

Renseignements supplémentaires: Type 'TestConsole.Programme+MyEnum' ne peut pas être mobilisé comme un non géré structure; non significative de la taille ou de la compensation peut être calculée.

Bien que ce code ne lance pas d'exception et d' size contient 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 l' .NET framework ne peut pas comprendre que l' enum est de 4 octets dans le premier exemple de code?

Mise à JOUR

La chose étrange est qu'un enum est considéré comme un struct par le compilateur car Marshal.Sizeof() echec 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 n'a pas à se plaindre enum n'étant pas un struct.

SOLUTION

Merci pour les nombreuses réponses. Je pourrais refactoriser ma méthode générique pour le faire fonctionner pour les structures ET les énumérations:

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

26voto

280Z28 Points 49515

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 ont auto champ de mise en page (§10.1.2); ...

Et les attentes de l' Marshal.SizeOf:

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

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

0voto

0699 Points 43

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

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X