【问题标题】:Get Enum by Custom Attribute (Generic)通过自定义属性获取枚举(通用)
【发布时间】:2016-07-07 22:56:42
【问题描述】:

有很多示例可以通过自定义属性获取枚举,例如这里 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 进行硬编码。

【问题讨论】:

  • 作为一个想法,您可以在方法中添加另一个通用参数,但您应该知道输入参数的含义和用法才能使用它进行搜索。例如,现在你可以有这个条件if(attribute.Description == description),但是当你传递一个泛型参数时呢?
  • 如果attribute 不是DescriptionAttribute,您将如何翻译:attribute.Description

标签: c# generics enums custom-attributes


【解决方案1】:

你可以添加一个接口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);
    }
}

或具有完整基类的等价物:

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 你甚至可以不使用Invoke直接调用你的函数来确保类型安全:if (valueFunc(attribute) == text)。但是真的很酷的答案。
    • @HimBromBeere 是一样的(只是Invoke的快捷方式)
    【解决方案3】:

    添加一个新的泛型类型

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

    并在 GetCustomerAttribute 中使用它

    var attribute = Attribute.GetCustomAttribute(field, typeof(K));
    

    【讨论】:

      猜你喜欢
      • 2020-07-19
      • 1970-01-01
      • 2023-03-09
      • 1970-01-01
      • 1970-01-01
      • 2011-07-03
      • 1970-01-01
      • 2019-09-13
      相关资源
      最近更新 更多