通过自定义属性获取枚举(通用)

Get Enum by Custom Attribute (Generic)

有很多示例,您可以像这里一样通过自定义属性获取枚举 Get Enum from Description attribute

public static class EnumEx
{
    public static T GetValueFromDescription<T>(string description)
    {
        var type = typeof(T);
        if(!type.IsEnum) throw new InvalidOperationException();
        foreach(var field in type.GetFields())
        {
            var attribute = Attribute.GetCustomAttribute(field,
                typeof(DescriptionAttribute)) as DescriptionAttribute;
            if(attribute != null)
            {
                if(attribute.Description == description)
                    return (T)field.GetValue(null);
            }
            else
            {
                if(field.Name == description)
                    return (T)field.GetValue(null);
            }
        }
        throw new ArgumentException("Not found.", "description");
        // or return default(T);
    }
}

但这里的问题是您必须对属性类型进行硬编码,即 typeof(DescriptionAttribute)) as DescriptionAttribute

如何将此示例转换为通用扩展,以便不必对 CustomAttributeType 进行硬编码。

这适用于您想要将值作为字符串进行比较的任何属性:

public static TEnum GetValueFromAttribute<TEnum, TAttribute>
           (string text, Func<TAttribute, string> valueFunc) where TAttribute : Attribute
{ 
   var type = typeof(TEnum);
   if(!type.IsEnum) throw new InvalidOperationException();
   foreach(var field in type.GetFields())
   {
       var attribute = Attribute.GetCustomAttribute(field, typeof(TAttribute)) as TAttribute;
       if(attribute != null)
       {
           if(valueFunc.Invoke(attribute) == text)
               return (TEnum)field.GetValue(null);
       }
       else
       {
           if(field.Name == text)
               return (TEnum)field.GetValue(null);
       }
   }
   throw new ArgumentException("Not found.", "text");
    // or return default(T);
}

你会这样称呼它:

 var value = GetValueFromAttribute<MyEnum, Description>("desc_text", a => a.Description);

您可以添加一个接口 IDescription,您的属性实现:

public interface IDescription
{
    string Description { get; }
}

public static class EnumEx
{
    public static T GetValueFromDescription<T, TAttribute>(string description) where TAttribute : Attribute, IDescription
    {
        var type = typeof(T);

        if (!type.IsEnum) throw new InvalidOperationException();

        foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Static))
        {
            var attribute = (IDescription)Attribute.GetCustomAttribute(field, typeof(TAttribute));

            if (attribute != null)
            {
                if (attribute.Description == description)
                {
                    return (T)field.GetValue(null);
                }
            }
            else
            {
                if (field.Name == description)
                {
                    return (T)field.GetValue(null);
                }
            }
        }

        throw new ArgumentException("Not found.", "description");
        // or return default(T);
    }
}

或等价于完整的基础 class:

public abstract class BaseDescriptionAttribute : Attribute
{
    public string Description { get; protected set; }
}

public static class EnumEx
{
    public static T GetValueFromDescription<T, TAttribute>(string description) where TAttribute : BaseDescriptionAttribute
    {
        var type = typeof(T);

        if (!type.IsEnum) throw new InvalidOperationException();

        foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Static))
        {
            var attribute = (BaseDescriptionAttribute)Attribute.GetCustomAttribute(field, typeof(TAttribute));

添加新的泛型类型

public static T GetValueFromDescription<T, K>(string description)

并在 GetCustomerAttribute

中使用它
var attribute = Attribute.GetCustomAttribute(field, typeof(K));