2010-04-17 18 views
34

Imaginemos que tenemos una enumeración:la conversión de un entero a un tipo de enumeración en caja sólo se conoce en tiempo de ejecución

enum Foo { A=1,B=2,C=3 } 

Si el tipo es conocido en tiempo de compilación, un reparto directo se puede utilizar para cambiar entre el enum- tipo y el tipo subyacente (por lo general int):

static int GetValue() { return 2; } 
... 
Foo foo = (Foo)GetValue(); // becomes Foo.B 

y el boxeo esto le da una caja de tipo Foo:

object o1 = foo; 
Console.WriteLine(o1.GetType().Name); // writes Foo 

(y, de hecho, puede caja como Foo y unbox como int, o una caja como int y unbox como Foo felizmente)

Sin embargo (el problema); si el tipo enum solo se conoce en el tiempo de ejecución, las cosas son ... más complicadas. Obviamente, es trivial colocarlo como int, pero ¿puedo guardarlo como Foo? (Idealmente sin usar genéricos y MakeGenericMethod, lo que sería feo). Convert.ChangeType arroja una excepción. ToString y Enum.Parse funciona, pero es horriblemente ineficaz.

yo pude ver los valores definidos (Enum.GetValues o Type.GetFields), pero que es muy difícil para [Flags], e incluso sin requeriría volver a la primera de tipo subyacente (que no es tan difícil, por suerte).

Pero; ¿Hay una forma más directa de obtener un valor del tipo subyacente correcto en un recuadro del tipo enum, donde el tipo solo se conoce en el tiempo de ejecución?

Respuesta

60

Creo que el método Enum.ToObject hará lo que quiera.

Type type= typeof(Foo); 
object o1 = Enum.ToObject(type,GetValue()); 
+2

How the $ (* &% $ (¡Echo de menos!) Gracias, eso es exactamente lo que quiero. –

+3

Fácil de perder. Parece un nombre de método terrible. Algo como 'Enum.FromValue' puede tener sido mejor. –

8

Sólo quería añadir algo a @aaronb's answer: que tenía que hacer esto mismo por algún código de asignación automática y descubrió que tenía que hacer varias comprobaciones con el fin de hacer que el código para tipos arbitrarios. En particular, los valores nulos y las enumeraciones que se pueden anotar te darán dolores de cabeza.

El código más infalible que tengo en este momento es la siguiente:

static object CastBoxedValue(object value, Type destType) 
{ 
    if (value == null) 
     return value; 

    Type enumType = GetEnumType(destType); 
    if (enumType != null) 
     return Enum.ToObject(enumType, value); 

    return value; 
} 

private static Type GetEnumType(Type type) 
{ 
    if (type.IsEnum) 
     return type; 

    if (type.IsGenericType) 
    { 
     var genericDef = type.GetGenericTypeDefinition(); 
     if (genericDef == typeof(Nullable<>)) 
     { 
      var genericArgs = type.GetGenericArguments(); 
      return (genericArgs[0].IsEnum) ? genericArgs[0] : null; 
     } 
    } 
    return null; 
} 

Si usted nunca puede tener un tipo anulable, simplemente ignore esto. :)

+0

Pensamientos valiosos, pero de hecho ya he eliminado cosas como 'Nullable ', 'List ' etc upstream de esto. –

+0

'Nullable.GetUnderlyingType' podría ser un poco más sencillo que inspeccionar los argumentos genéricos. – Craig

Cuestiones relacionadas