2010-11-04 22 views
7

Estoy seguro de que esto es bastante trivial, pero no puedo hacerlo bien.Establecer una enumeración en su valor predeterminado

public static string DoSomething(this Enum value) 
{ 
    if (!Enum.IsDefined(value.GetType(), value)) 
    { 
     // not a valid value, assume default value 
     value = default(value.GetType()); 
    } 

    // ... do some other stuff 
} 

La línea de value = default(value.GetType()); no compila, pero espero que pueda ver lo que estoy tratando. Necesito configurar el param Enum al valor predeterminado de su propio tipo.

+0

¿Cómo puede ¿incluso llama a este método sin que el 'valor' se defina en la enumeración del mismo tipo que 'valor'? –

+0

@Paw, esa es la forma en que enum funciona. Puede almacenar cualquier valor int en una entrada, ya sea definida o no. – fearofawhackplanet

+0

@fearofawhackplanet, solo trato de entender lo que estás tratando de hacer. Si desea convertir un int a una enumeración o tal vez una cadena a una enumeración? –

Respuesta

1

Activator.CreateInstance(typeof(ConsoleColor)) parece funcionar

+0

. Necesita un modelo difícil para esto. (ConsoleColor) Activator.CreateInstance (typeof (ConsoleColor)) –

+0

@Paw, ¿cómo harías eso en el ejemplo del miedo (con un tipo dinámico) –

+0

no puedes, es por eso que no creo que funcione con Activator. –

-1

Enum por defecto tiene su first value como default value

+3

de nuevo, ¿cómo soluciona esto mi problema? (y ni siquiera es técnicamente correcto, no creo) – fearofawhackplanet

+2

-1: Lo sentimos, pero el valor predeterminado para cada enumeración es 0, incluso si 0 es un valor no válido para la enumeración. Pruebe 'enum MyEnum {M1 = -1, M2 = 1}; MyEnum e = predeterminado (MyEnum); ... Console.WriteLine ("{0}", e); 'Escribe' 0' –

-1

¿Ha pensado lo que es un método genérico?

public static string DoSomething<T>(Enum value) 
{ 
    if (!Enum.IsDefined(typeof(T), value)) 
    { 
     value = (T)Enum.ToObject(typeof(T), 0); 
    } 
    // ... do some other stuff 
} 

La persona que llama debe saber el tipo.

+3

El 'donde T: enum' no existe en C#. :-(Ese es todo el problema aquí. –

+0

Ah cierto, eliminé eso. –

+0

Aún así funcionaría, sin el 'dónde'. Solo necesitaría probar/atrapar para asegurarse de que su elenco no explotara. lanzar una nueva excepción a la persona que llama si T no era una enumeración. –

5

No estoy realmente seguro de lo que estamos tratando de hacer aquí, pero una versión de la línea 'por defecto', que hace compilar es esto:

value = (Enum)Enum.GetValues(value.GetType()).GetValue(0); 

O, aún más limpio (de la pata, en los comentarios, gracias):

value = (Enum) Enum.ToObject(value.GetType(), 0); 

Esta segunda versión sólo funciona correctamente si usted sabe primer elemento de la enumeración tiene un valor de cero.

+0

o valor = (Enum) Enum.ToObject (value.GetType(), 0); –

+0

@paw ¿Qué pasa si usted? re usando esto: 'enum Foo {a = 1, b = 2}'? +1 a Will, parece bastante robusto –

+0

@Paw: No. 0 no es un valor definido para todas las enumeraciones. –

2

Usted podría hacer lo Paw is suggesting, incluso con una limitación genérica, si se pudiera mover este método para su propia clase:

public abstract class Helper<T> 
{ 
    public static string DoSomething<TEnum>(TEnum value) where TEnum: struct, T 
    { 
     if (!Enum.IsDefined(typeof(TEnum), value)) 
     { 
      value = default(TEnum); 
     } 

     // ... do some other stuff 

     // just to get code to compile 
     return value.ToString(); 
    } 
} 

public class EnumHelper : Helper<Enum> { } 

allí tendría que hacer, por ejemplo:

MyEnum x = MyEnum.SomeValue; 
MyEnum y = (MyEnum)100; // Let's say this is undefined. 

EnumHelper.DoSomething(x); // generic type of MyEnum can be inferred 
EnumHelper.DoSomething(y); // same here 

Como señala Konrad Rudolph en un comentario, default(TEnum) en el código anterior evaluará a 0, independientemente de si se define o no un valor para 0 para el tipo dado TEnum. Si eso no es lo que desea, Will's answer proporciona ciertamente la forma más fácil de obtener el primer definido valor ((TEnum)Enum.GetValues(typeof(TEnum)).GetValue(0)).

Por otro lado, si quieres llevar esto al extremo , y almacenar en caché el resultado para que no siempre se tiene a la caja, usted podría hacer eso:

public abstract class Helper<T> 
{ 
    static Dictionary<Type, T> s_defaults = new Dictionary<Type, T>(); 

    public static string DoSomething<TEnum>(TEnum value) where TEnum: struct, T 
    { 
     if (!Enum.IsDefined(typeof(TEnum), value)) 
     { 
      value = GetDefault<TEnum>(); 
     } 

     // ... do some other stuff 

     // just to get code to compile 
     return value.ToString(); 
    } 

    public static TEnum GetDefault<TEnum>() where TEnum : struct, T 
    { 
     T definedDefault; 
     if (!s_defaults.TryGetValue(typeof(TEnum), out definedDefault)) 
     { 
      // This is the only time you'll have to box the defined default. 
      definedDefault = (T)Enum.GetValues(typeof(TEnum)).GetValue(0); 
      s_defaults[typeof(TEnum)] = definedDefault; 
     } 

     // Every subsequent call to GetDefault on the same TEnum type 
     // will unbox the same object. 
     return (TEnum)definedDefault; 
    } 
} 
+0

Su código no compila para mí (Mono C#). –

+0

@Konrad: Eso * puede * ser porque tuve un error tipográfico ('TEnumvalue'-sin espacio). Además, no incluí un valor de retorno. Me gustaría saber si se compila para Mono ahora que actualicé el ejemplo. –

+0

Ya lo había corregido, no ayudaba. Curiosamente, ahora compila (+1, ¡hack elegante!) - pero tiene el mismo problema que las otras soluciones, a saber, 'default' realmente devuelve' 0' que puede ser un valor indefinido en la enumeración real y por lo tanto no es el resultado correcto Existe el problema adicional de que su solución ya no funciona como un método de extensión. –

Cuestiones relacionadas