【问题标题】:Get Enum from Description attribute [duplicate]从描述属性获取枚举[重复]
【发布时间】:2011-05-21 01:03:15
【问题描述】:

可能重复:
Finding an enum value by its Description Attribute

我有一个通用扩展方法,它从Enum 获取Description 属性:

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

所以我可以...

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

现在,我正在尝试在另一个方向上计算出等效的功能,例如...

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

【问题讨论】:

    标签: c# .net attributes enums


    【解决方案1】:
    public static class EnumEx
    {
        public static T GetValueFromDescription<T>(string description) where T : Enum
        {
            foreach(var field in typeof(T).GetFields())
            {
                if (Attribute.GetCustomAttribute(field,
                typeof(DescriptionAttribute)) is DescriptionAttribute attribute)
                {
                    if (attribute.Description == description)
                        return (T)field.GetValue(null);
                }
                else
                {
                    if (field.Name == description)
                        return (T)field.GetValue(null);
                }
            }
    
            throw new ArgumentException("Not found.", nameof(description));
            // Or return default(T);
        }
    }
    

    用法:

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

    【讨论】:

    • 如果你在字符串前面加上“this”关键字 ... public static T GetValueFromDescription(this string description) ... 它变成一个扩展方法,你可以使用如下语法: var x = "大熊猫".GetValueFromDescription();
    • 如果描述无效,如何查找? with:var x = EnumEx.GetValueFromDescription&lt;Animal&gt;("Dinosaur"); 我知道它会抛出异常。但是 x 会包含什么?
    • @VenkatRenukaPrasad 如果它无论如何都会抛出,那么x 什么都没有,你不必担心。有异常处理机制并处理。
    • 可能想要像这样进行不区分大小写的比较。 if (string.Equals(attribute.Description,description, StringComparison.InvariantCultureIgnoreCase)) return (T)field.GetValue(null);它抓住了我。
    • 为了让上面的代码更好地工作,将“foreach(var field in type.GetFields())”这一行更改为“foreach(var field in type.GetFields(BindingFlags.Public | BindingFlags.Static ))”。否则在下面的else中,该字段的名称是'value__'而不是真实名称。
    【解决方案2】:

    而不是扩展方法,只需尝试几个静态方法

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

    在这里使用

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

    【讨论】:

    • value.ToString() 很贵,不要调用两次(.. 如果重要的话)...
    • @nawfal,比什么贵?
    • @MEMark 我不记得我当时在想什么,但可能是this
    • 如果您将方法更改为在左大括号前添加where T : Enum,则无需在运行时检查typeof(T)
    • @ATD 你是对的,我当时忘记了这一点。但是,它在框架中受支持,因此您可以使用 Fody.ExtraConstraints 获得相同的效果,完全编译并像指定了 where T : Enum 一样工作。语法为public void MethodWithEnumConstraint&lt;[EnumConstraint] T&gt;() {...},编译为public void MethodWithEnumConstraint&lt;T&gt;() where T: struct, Enum {...}
    【解决方案3】:

    除非您有 Web 服务,否则该解决方案效果很好。

    您需要执行以下操作,因为描述属性不可序列化。

    [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;
    }
    

    【讨论】:

    • EnumMemberAttribute 的命名空间是什么?
    • 这正是我想要的。我喜欢的两个亮点是,我的枚举也以 1 开头。其次,它的枚举成员作为它的 wcf。非常感谢:)
    • @AshishJain 这是System.Runtime.Serialization
    【解决方案4】:

    应该很简单,和你之前的方法相反;

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

    用法:

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

    【讨论】:

      【解决方案5】:

      您不能扩展 Enum,因为它是一个静态类。您只能扩展一个类型的实例。考虑到这一点,您将不得不自己创建一个静态方法来执行此操作;与您现有的方法 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.");
          }
      }
      

      它的用法是这样的:

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

      【讨论】:

      • 这在逻辑上是错误的(尽管可以在合理的情况下工作)。例如,如果你有像Animal { ("Giant Panda")GiantPanda, ("GiantPanda")Tiger } 这样的枚举并且你调用GetEnumFromString("GiantPanda"),你会得到GiantPanda 回来,但我希望Tiger 回来。具有读取枚举字符串或其描述的功能。将两者混合是一种糟糕的 API 风格,可能会使客户端感到困惑。或者可能是它防止用户错误的好风格:)
      【解决方案6】:

      您需要遍历Animal中的所有枚举值,并返回与您需要的描述相匹配的值。

      【讨论】:

      • 是的,它得到了正确的枚举类型,我有点卡住了。
      猜你喜欢
      • 1970-01-01
      • 2018-01-07
      • 1970-01-01
      • 1970-01-01
      • 2013-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多