2010-11-22 14 views
5

Actualmente estoy implementando una asociación de cadenas y enumeraciones basadas en this suggestion. Siendo así, tengo un atributo Description asociado con cada elemento enum. En esa página también hay una función que devuelve la cadena de la descripción en función de la enumeración dada. Lo que me gustaría implementar ahora es la función inversa, es decir, dada una cadena de entrada, busque la enumeración con la descripción correspondiente, si existe, devolviendo nulo en caso contrario.Cadena a Enum con descripción

He intentado (T) Enum.Parse(typeof(T), "teststring") pero arroja una excepción.

+0

posible duplicado de [¿Puede acceder a una descripción larga para un valor de enumeración específico.] (Http://stackoverflow.com/questions/1473870/can-you-access-a-long-description-for-a-specific -enum-value) – NotMe

Respuesta

12

Usted tiene que escribir su propio método inverso. El método stock de Parse() obviamente no conoce los atributos de su descripción.

Algo como esto debería funcionar:

public static T GetEnumValueFromDescription<T>(string description) 
{ 
    MemberInfo[] fis = typeof(T).GetFields(); 

    foreach (var fi in fis) 
    { 
     DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false); 

     if (attributes != null && attributes.Length > 0 && attributes[0].Description == description) 
      return (T)Enum.Parse(typeof(T), fi.Name); 
    } 

    throw new Exception("Not found"); 
} 

usted querrá encontrar un mejor cosa que hacer que una excepción si no se encontró el valor de enumeración, sin embargo. :)

+1

¡Gran solución! En lugar de lanzar una excepción, fui con el análisis enum predeterminado. Esto cubre el escenario donde es posible que no tenga un atributo de descripción en cada opción en una enumeración. – norepro

+0

Esto no funcionó para mí. Tuve que hacer algunos cambios. El siguiente código es del interior de cada uno. Espero que ayude a alguien :) var atributos = fi.CustomAttributes; if (attributes! = Null && attributes.Count()> 0 && (string) attributes.First(). NamedArguments.First(). TypedValue.Value == description) return (int) Enum.Parse (typeof (TEnum), fi.Name); – rsy

0

This answer a una pregunta relacionada muestra cómo recuperar los atributos para un tipo determinado. Puede usar un enfoque similar para comparar una cadena dada con los atributos de descripción de Enum.

2
static string GetEnumDescription<T>(T 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(); 
    } 
} 

static T ParseDescriptionToEnum<T>(string description) { 
    Array array = Enum.GetValues(typeof(T)); 
    var list = new List<T>(array.Length); 
    for(int i = 0; i < array.Length; i++) { 
     list.Add((T)array.GetValue(i)); 
    } 

    var dict = list.Select(v => new { 
        Value = v, 
        Description = GetEnumDescription(v) } 
       ) 
        .ToDictionary(x => x.Description, x => x.Value); 
    return dict[description]; 
} 

No hice ningún intento de comprobación de errores. Tenga en cuenta que no es necesario crear el diccionario en cada llamada al método, pero soy demasiado perezoso para solucionarlo.

Uso:

enum SomeEnum { 
    [Description("First Value")] 
    FirstValue, 
    SecondValue 
} 

SomeEnum value = ParseDescriptionToEnum<SomeEnum>("First Value"); 

Una prueba que pasa:

[Fact] 
public void Can_parse_a_value_with_a_description_to_an_enum() { 
    string description = "First Value"; 
    SomeEnum value = ParseDescriptionToEnum<SomeEnum>(description); 
    Assert.Equal(SomeEnum.FirstValue, value); 
} 

[Fact] 
public void Can_parse_a_value_without_a_description_to_an_enum() { 
    string description = "SecondValue"; 
    SomeEnum value = ParseDescriptionToEnum<SomeEnum>(description); 
    Assert.Equal(SomeEnum.SecondValue, value); 
} 
1

Habría votado la respuesta de Anna, pero no tengo la reputación de hacerlo. Con parte de esto basado en su respuesta, aquí hay una solución bidireccional que se me ocurrió. El suministro de un método DefaultValue to ParseEnum cubre casos en los que el mismo Enum puede tener un valor por defecto diferente en función de su uso.

public static string GetDescription<T>(this object enumerationValue) where T : struct 
    { 
     // throw an exception if enumerationValue is not an Enum 
     Type type = enumerationValue.GetType(); 
     if (!type.IsEnum) 
     { 
      throw new ArgumentException("EnumerationValue must be of Enum type", "enumerationValue"); 
     } 

     //Tries to find a DescriptionAttribute for a potential friendly name for the enum 
     MemberInfo[] memberInfo = type.GetMember(enumerationValue.ToString()); 
     if (memberInfo != null && memberInfo.Length > 0) 
     { 
      DescriptionAttribute[] attributes = (DescriptionAttribute[])memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false); 

      if (attributes != null && attributes.Length > 0) 
      { 
       //Pull out the description value 
       return attributes[0].Description; 
      } 
     } 

     //In case we have no description attribute, we'll just return the ToString of the enum 
     return enumerationValue.ToString(); 
    } 

    public static T ParseEnum<T>(this string stringValue, T defaultValue) 
    { 
     // throw an exception if T is not an Enum 
     Type type = typeof(T); 
     if (!type.IsEnum) 
     { 
      throw new ArgumentException("T must be of Enum type", "T"); 
     } 

     //Tries to find a DescriptionAttribute for a potential friendly name for the enum 
     MemberInfo[] fields = type.GetFields(); 

     foreach (var field in fields) 
     { 
      DescriptionAttribute[] attributes = (DescriptionAttribute[])field.GetCustomAttributes(typeof(DescriptionAttribute), false); 

      if (attributes != null && attributes.Length > 0 && attributes[0].Description == stringValue) 
      { 
       return (T)Enum.Parse(typeof(T), field.Name); 
      } 
     } 

     //In case we couldn't find a matching description attribute, we'll just return the defaultValue that we provided 
     return defaultValue;    
    } 
1

También puede usar Humanizer para eso. Para obtener la descripción que escribe:

EAssemblyUnit.eUCAL1.Humanize(); 

y para obtener la enumeración de vuelta de la descripción, que es lo que desea, puede escribir:

"UCAL1".DehumanizeTo<EAssemblyUnit>(); 

responsabilidad: yo soy el creador de Humanizer.

Cuestiones relacionadas