2010-12-06 16 views
173

Duplicar posibles:
Finding an enum value by its Description AttributeGet Enumeración de atributo Descripción

Tengo un método de extensión genérica que recibe el atributo Description de un Enum:

enum Animal 
{ 
    [Description("")] 
    NotSet = 0, 

    [Description("Giant Panda")] 
    GiantPanda = 1, 

    [Description("Lesser Spotted Anteater")] 
    LesserSpottedAnteater = 2 
} 

public static string GetDescription(this Enum value) 
{    
    FieldInfo field = value.GetType().GetField(value.ToString()); 

    DescriptionAttribute attribute 
      = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) 
       as DescriptionAttribute; 

    return attribute == null ? value.ToString() : attribute.Description; 
} 

así que puede hacer ...

string myAnimal = Animal.GiantPanda.GetDescription(); // = "Giant Panda" 

ahora, estoy tratando de averiguar la función equivalente en la otra dirección, algo así como ...

Animal a = (Animal)Enum.GetValueFromDescription("Giant Panda", typeof(Animal)); 

Respuesta

241
public static class EnumEx 
{ 
    public static T GetValueFromDescription<T>(string description) 
    { 
     var type = typeof(T); 
     if(!type.IsEnum) throw new InvalidOperationException(); 
     foreach(var field in type.GetFields()) 
     { 
      var attribute = Attribute.GetCustomAttribute(field, 
       typeof(DescriptionAttribute)) as DescriptionAttribute; 
      if(attribute != null) 
      { 
       if(attribute.Description == description) 
        return (T)field.GetValue(null); 
      } 
      else 
      { 
       if(field.Name == description) 
        return (T)field.GetValue(null); 
      } 
     } 
     throw new ArgumentException("Not found.", "description"); 
     // or return default(T); 
    } 
} 

Uso:

var panda = EnumEx.GetValueFromDescription<Animal>("Giant Panda"); 
+36

Si agrega la palabra clave "this" delante de la cadena ... public static T GetValueFromDescription (esta descripción de cadena) ...se convierte en un método de extensión y puede usar la sintaxis como: var x = "Giant Panda" .GetValueFromDescription (); –

+0

Me gusta este enfoque. Funciona para mí y es elegante y al grano. – beaudetious

+0

¿Cómo se puede encontrar si la descripción no es válida? con: 'var x = EnumEx.GetValueFromDescription (" Dinosaurio ");' Sé que arrojaría una excepción. Pero, ¿qué contendría x? –

0

Es necesario para recorrer todos los valores de enumeración en animales y devolver el valor que coincida con la descripción que necesita.

+0

sí, está obteniendo el tipo de letra correcto que estoy un poco atascado. – fearofawhackplanet

2

No se puede ampliar Enum ya que es una clase estática. Solo puede extender instancias de un tipo. Con esto en mente, vas a tener que crear un método estático para hacer esto; lo siguiente debe funcionar cuando se combina con el método existente GetDescription:

public static class EnumHelper 
{ 
    public static T GetEnumFromString<T>(string value) 
    { 
     if (Enum.IsDefined(typeof(T), value)) 
     { 
      return (T)Enum.Parse(typeof(T), value, true); 
     } 
     else 
     { 
      string[] enumNames = Enum.GetNames(typeof(T)); 
      foreach (string enumName in enumNames) 
      { 
       object e = Enum.Parse(typeof(T), enumName); 
       if (value == GetDescription((Enum)e)) 
       { 
        return (T)e; 
       } 
      } 
     } 
     throw new ArgumentException("The value '" + value 
      + "' does not match a valid enum name or description."); 
    } 
} 

Y el uso de la que sería algo como esto:

Animal giantPanda = EnumHelper.GetEnumFromString<Animal>("Giant Panda"); 
+2

Esto es lógicamente incorrecto (aunque puede funcionar en escenarios sensibles). Por ejemplo, si tienes enum como 'Animal {(" Panda Gigante ") GiantPanda, (" GiantPanda ") Tiger}' y llamas 'GetEnumFromString (" GiantPanda ")', obtendrás 'GiantPanda' de vuelta, pero espero' Tiger' de nuevo. Tiene una función para leer cadena enum o su descripción. Mezclar ambos es un mal estilo API y puede confundir a los clientes. O puede ser su buen estilo para evitar errores del usuario :) – nawfal

4

En caso ser bastante directo, es exactamente el reverso de su método anterior;

public static int GetEnumFromDescription(string description, Type enumType) 
{ 
    foreach (var field in enumType.GetFields()) 
    { 
     DescriptionAttribute attribute 
      = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute))as DescriptionAttribute; 
     if(attribute == null) 
      continue; 
     if(attribute.Description == description) 
     { 
      return (int) field.GetValue(null); 
     } 
    } 
    return 0; 
} 

Uso:

Console.WriteLine((Animal)GetEnumFromDescription("Giant Panda",typeof(Animal))); 
37

en lugar de los métodos de extensión, sólo trata de un par de métodos estáticos

public static class Utility 
{ 
    public static string GetDescriptionFromEnumValue(Enum value) 
    { 
     DescriptionAttribute attribute = value.GetType() 
      .GetField(value.ToString()) 
      .GetCustomAttributes(typeof (DescriptionAttribute), false) 
      .SingleOrDefault() as DescriptionAttribute; 
     return attribute == null ? value.ToString() : attribute.Description; 
    } 

    public static T GetEnumValueFromDescription<T>(string description) 
    { 
     var type = typeof(T); 
     if (!type.IsEnum) 
      throw new ArgumentException(); 
     FieldInfo[] fields = type.GetFields(); 
     var field = fields 
         .SelectMany(f => f.GetCustomAttributes(
          typeof(DescriptionAttribute), false), (
           f, a) => new { Field = f, Att = a }) 
         .Where(a => ((DescriptionAttribute)a.Att) 
          .Description == description).SingleOrDefault(); 
     return field == null ? default(T) : (T)field.Field.GetRawConstantValue(); 
    } 
} 

y utilizar aquí

var result1 = Utility.GetDescriptionFromEnumValue(
    Animal.GiantPanda); 
var result2 = Utility.GetEnumValueFromDescription<Animal>(
    "Lesser Spotted Anteater"); 
+0

'value.ToString()' es caro, no lo llame dos veces (... si es importante) ... – nawfal

+0

@nawfal, ¿caro comparado con qué? – MEMark

+0

@MEMark No recuerdo lo que estaba pensando entonces, pero puede ser [esto] (http://stackoverflow.com/a/17034624/661933) – nawfal

12

La solución funciona bien, excepto Si tienes un Servicio web.

Debería hacer lo siguiente ya que el atributo de descripción no es serializable.

[DataContract] 
public enum ControlSelectionType 
{ 
    [EnumMember(Value = "Not Applicable")] 
    NotApplicable = 1, 
    [EnumMember(Value = "Single Select Radio Buttons")] 
    SingleSelectRadioButtons = 2, 
    [EnumMember(Value = "Completely Different Display Text")] 
    SingleSelectDropDownList = 3, 
} 

public static string GetDescriptionFromEnumValue(Enum value) 
{ 
     EnumMemberAttribute attribute = value.GetType() 
      .GetField(value.ToString()) 
      .GetCustomAttributes(typeof(EnumMemberAttribute), false) 
      .SingleOrDefault() as EnumMemberAttribute; 
     return attribute == null ? value.ToString() : attribute.Value; 
} 
Cuestiones relacionadas