2010-04-16 34 views
279

Duplicar posible:
Getting attributes of Enum’s valueCómo obtener la descripción de C# Enum del valor?

tengo una enumeración con la descripción atribuye así:

public enum MyEnum 
{ 
    Name1 = 1, 
    [Description("Here is another")] 
    HereIsAnother = 2, 
    [Description("Last one")] 
    LastOne = 3 
} 

me encontré con este trozo de código para recuperar la descripción basada en una Enum

public static string GetEnumDescription(Enum value) 
{ 
    FieldInfo fi = value.GetType().GetField(value.ToString()); 

    DescriptionAttribute[] attributes = 
     (DescriptionAttribute[])fi.GetCustomAttributes(
     typeof(DescriptionAttribute), 
     false); 

    if (attributes != null && 
     attributes.Length > 0) 
     return attributes[0].Description; 
    else 
     return value.ToString(); 
} 

Esto me permite escribir código como:

var myEnumDescriptions = from MyEnum n in Enum.GetValues(typeof(MyEnum)) 
         select new { ID = (int)n, Name = Enumerations.GetEnumDescription(n) }; 

Lo que quiero hacer es si conozco el valor de enumeración (por ejemplo, 1) - ¿cómo puedo recuperar la descripción? En otras palabras, ¿cómo puedo convertir un número entero en un "valor Enum" para pasar a mi método GetDescription?

+0

(! Atributos = null) será siempre cierto y demás es redundante. – Jeff

+1

espacio de nombres requerido para Descripción es System.ComponentModel –

Respuesta

277
int value = 1; 
string description = Enumerations.GetEnumDescription((MyEnum)value); 

El defecto subyacente tipo de datos para una enum en C# es un int, que sólo puede echarlo.

+2

perfecto. Exactamente lo que quería. ¡Sabía que iba a ser simple! Ahora, si stackoverflow simplemente me dejara aceptar esta respuesta ... dice que necesito esperar 7 minutos. – davekaro

+41

¿Por qué no encuentro ninguna clase Enumerations en .Net framework? –

+53

La clase Enumerations es algo que la persona que hizo la pregunta se escribió a sí misma y la función GetEnumDescription() está en la pregunta. –

5

No puede hacer esto fácilmente de forma genérica: solo puede convertir un número entero en un tipo específico de enumeración. Como ha demostrado Nicholas, este es un elenco trivial si solo te importa un tipo de enumeración, pero si quieres escribir un método genérico que pueda manejar diferentes tipos de enumeraciones, las cosas se complican un poco. ¿Quieres un método a lo largo de las líneas de:

public static string GetEnumDescription<TEnum>(int value) 
{ 
    return GetEnumDescription((Enum)((TEnum)value)); // error! 
} 

pero esto da lugar a un error de compilación que "int no se puede convertir a TEnum" (y si se trabaja en torno a este, que "TEnum no se puede convertir a Enum ").Así que hay que engañar al compilador mediante la inserción de moldes de objetar:

public static string GetEnumDescription<TEnum>(int value) 
{ 
    return GetEnumDescription((Enum)(object)((TEnum)(object)value)); // ugly, but works 
} 

Ahora puede llamar a esto para obtener una descripción para cualquier tipo de enumeración está a la mano:

GetEnumDescription<MyEnum>(1); 
GetEnumDescription<YourEnum>(2); 
+0

¿Cómo es "GetEnumDescription (1);" mejor que GetEnumDescription ((MyEnum) 1); ? – davekaro

+0

@davekaro: implementado de esta manera, no es mucho mejor, pero una implementación más sólida basada en genéricos podría hacer esto sin el molde explícito, por lo que no se arriesga a excepciones no controladas si el número no coincide realmente con ninguno de los valores enum. – Aaronaught

+0

Interesante. Solo para aclarar a los lectores futuros: no se obtendrá una excepción no controlada en un lanzamiento explícito si el número no coincide con uno de los valores enum (se podría decir "MyEnum value = (MyEnum) 5;" y esa línea ejecute bien, pero usted bombardearía en la primera línea de GetEnumDescription() como se implementó en la pregunta original (porque GetField() devolverá nulo ya que no puede encontrar ningún campo coincidente con ese valor). (Para protegerse de eso, nosotros ' d necesita comprobar Enum.IsDefined() primero y devolver null o una cadena vacía, o simplemente arrojar una ArgumentOutOfRangeException nosotros mismos.) –

68

He implementado esto en una genérico, con seguridad de forma en Unconstrained Melody - que usaría:

string description = Enums.GetDescription((MyEnum)value); 

Este:

  • Asegura (con limitaciones de tipo genérico) que el valor de verdad es un valor de enumeración
  • Evita el boxeo en la solución actual
  • cachés todas las descripciones de evitar el uso de reflexión en cada llamada
  • tiene un montón de otra métodos, incluyendo la capacidad de analizar el valor de la descripción

que dan cuenta de la respuesta del núcleo era simplemente el reparto de un int a MyEnum, pero si usted está haciendo una gran cantidad de enumeración trabajar vale la pena pensar sobre el uso sin restricciones Melody :)

+0

¿No es "valor" un int? Entonces, no Enum.GetDescription ((MyEnum) valor) simplemente envía el int a MyEnum? – davekaro

+0

@davekaro: Envía el int a MyEnum, pero no podrías llamarlo con ningún enum, incluida una referencia "Enum". Básicamente es como tu código, pero con algunos genéricos mágicos –

+1

@JonSkeet No veo este método en Enum s.cs en https://code.google.com/p/unconstrained-melody/downloads/detail?name=UnconstrainedMelody-0.0.0.2-src.zip&can=2&q= – tom

19

Para que esto sea más fácil de usar, escribí una extensión genérica:

public static string ToDescription<TEnum>(this TEnum EnumValue) where TEnum : struct 
{ 
    return Enumerations.GetEnumDescription((Enum)(object)((TEnum)EnumValue)); 
} 

ahora puedo escribir:

 MyEnum my = MyEnum.HereIsAnother; 
     string description = my.ToDescription(); 
     System.Diagnostics.Debug.Print(description); 

Nota: reemplazar "enumeraciones" por encima con su nombre de la clase

50

Puse el código de la respuesta aceptada en un método de extensión genérico, por lo que podría ser utilizado para todo tipo de objetos:

public static string DescriptionAttr<T>(this T source) 
{ 
    FieldInfo fi = source.GetType().GetField(source.ToString()); 

    DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(
     typeof(DescriptionAttribute), false); 

    if (attributes != null && attributes.Length > 0) return attributes[0].Description; 
    else return source.ToString(); 
} 

Usando una enumeración como en el post original, o cualquier otra clase cuyo establecimiento está decorado con la descripción del atributo, el código puede ser consumido como esto:

string enumDesc = MyEnum.HereIsAnother.DescriptionAttr(); 
string classDesc = myInstance.SomeProperty.DescriptionAttr(); 
+2

string classDesc = myInstance.SomeProperty.DescriptionAttr(); ¡Eso no funcionará! Digamos que tienes clase Test {public int TestInt {get; establecer;}}. Entonces, si llama a una nueva Prueba(). TestInt.DescriptionAttr() obtendrá una excepción de referencia nula - 0.GetType(). GetField ("0") – Vladimirs

Cuestiones relacionadas