2010-11-22 17 views
5

現在、this suggestionに基づいて文字列と列挙子の関連付けを実装しています。つまり、すべてのenum要素に関連付けられた属性はDescriptionです。このページには、指定されたenumに基づいて説明の文字列を返す関数もあります。私が今実装しようとしているのは逆関数です。つまり、対応する記述が存在する場合は入力文字列を列挙し、それ以外の場合はnullを返します。文字列と列挙型の説明

私は(T) Enum.Parse(typeof(T), "teststring")を試しましたが、例外がスローされます。

+0

可能な複製[特定の列挙値の長い説明にアクセスできるかどうか](http://stackoverflow.com/questions/1473870/can-you-access-a-long-description-for-a-specific -enum-value) – NotMe

答えて

12

をあなたがあなた自身の逆の方法を記述する必要があります。株式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

素晴らしいソリューション!例外をスローするのではなく、デフォルトの列挙型解析を行った。これは、列挙のすべてのオプションに説明属性を持たないシナリオをカバーしています。 – norepro

+0

これは私にとってはうまくいかなかった。いくつかの変更を加えなければならなかった。下のコードはそれぞれの内部のコードです。希望誰かを助ける:) var attributes = 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関連する質問は、特定の種類の属性を取得する方法を示しています。同様の方法を使用して、指定された文字列を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]; 
} 

私はエラーチェックを試みていません。辞書はメソッドの呼び出しごとに作成する必要はありませんが、私はそれを修正するのが面倒です。

使用法:

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

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

渡しテスト:

[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だろうが、私はそうする評判はない。彼女の答えに基づいてこれの一部をここに私が思いついた2ウェイの解決策です。 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の生みの親です。