【问题标题】:String to Enum with Description带有描述的枚举字符串
【发布时间】:2015-03-10 21:39:53
【问题描述】:

我目前正在基于this suggestion 实现字符串和枚举的关联。也就是说,我有一个与每个枚举元素关联的 Description 属性。在该页面上还有一个函数,它根据给定的枚举返回描述的字符串。我现在要实现的是reverse函数,即给定一个输入字符串查找枚举,如果它存在对应的描述,否则返回null。

我尝试了(T) Enum.Parse(typeof(T), "teststring"),但它引发了异常。

【问题讨论】:

标签: c# enums


【解决方案1】:

您必须编写自己的反向方法。股票 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");
}

不过,如果找不到枚举值,您会想找到比抛出异常更好的方法。 :)

【讨论】:

  • 很好的解决方案!我没有抛出异常,而是使用了默认的枚举解析。这涵盖了枚举中的每个选项可能没有描述属性的情况。
  • 这对我不起作用。不得不做一些改变。下面的代码来自 for each 内部。希望它可以帮助某人:) 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);
【解决方案2】:

您也可以为此使用Humanizer。要获取您编写的描述:

EAssemblyUnit.eUCAL1.Humanize();

要从描述中取回枚举,这就是你想要的,你可以这样写:

"UCAL1".DehumanizeTo<EAssemblyUnit>();

免责声明:我是 Humanizer 的创造者。

【讨论】:

    【解决方案3】:
    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);
    }
    

    【讨论】:

      【解决方案4】:

      我会赞成 Anna 的回答,但我没有这样做的声誉。根据她的回答,部分内容是我提出的一种双向解决方案。为 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;            
          }
      

      【讨论】:

        【解决方案5】:

        This answer 到一个相关问题显示如何检索给定类型的属性。您可以使用类似的方法将给定字符串与Enum 的描述属性进行比较。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-10-24
          • 2012-10-15
          • 1970-01-01
          • 1970-01-01
          • 2015-12-30
          相关资源
          最近更新 更多