2010-11-22 120 views
5

我目前正在實現一個基於this suggestion字符串和枚舉associations。那是,我有一個Description屬性與每個枚舉元素相關聯。在該頁面上還有一個函數,該函數根據給定的枚舉返回描述的字符串。我現在要實現的是反向函數,即給定一個輸入字符串查找帶有相應描述的枚舉(如果存在),否則返回null。字符串到枚舉與描述

我試過(T) Enum.Parse(typeof(T), "teststring")但它會拋出異常。

+0

可能重複的[你可以訪問一個特定枚舉值的長描述。](http://stackoverflow.com/questions/1473870/can-you-access-a-long-description-for-a-specific - 價值) – NotMe 2010-11-22 20:04:42

回答

12

你必須寫自己的逆向方法:

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

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

即通過測試。股票Parse()方法顯然不知道你的描述屬性。

像這樣的東西應該工作:

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"); 
} 

你要找到一個更好的東西不是拋出一個異常,如果沒有找到枚舉值做,雖然。 :)

+1

偉大的解決方案!我沒有拋出異常,而是使用默認的枚舉分析。這涵蓋了您可能沒有關於枚舉中每個選項的description屬性的場景。 – norepro 2011-12-01 00:45:30

0

This answer到相關問題顯示如何檢索給定類型的屬性。您可以使用類似的方法將給定的字符串與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]; 
} 

我沒有嘗試進行錯誤檢查。請注意,字典不需要在每次調用該方法時創建,但我懶得解決這個問題。

用法:

[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

我會upvoted安娜的答案,但我沒有這樣做的聲譽。這部分基於她的答案,這是我提出的一種雙向解決方案。向ParseEnum方法提供defaultValue包括相同Enum根據其使用情況可能具有不同默認值的情況。

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

您也可以使用Humanizer。爲了讓你寫的說明:

EAssemblyUnit.eUCAL1.Humanize(); 

,並得到枚舉從描述,這是你想要的時候,你可以這樣寫:

"UCAL1".DehumanizeTo<EAssemblyUnit>(); 

免責聲明:我Humanizer的創造者。