如何获取枚举的自定义属性值?

Posted

技术标签:

【中文标题】如何获取枚举的自定义属性值?【英文标题】:How to get Custom Attribute values for enums? 【发布时间】:2011-07-03 03:16:54 【问题描述】:

我有一个枚举,其中每个成员都应用了一个自定义属性。如何检索存储在每个属性中的值?

现在我这样做:

var attributes = typeof ( EffectType ).GetCustomAttributes ( false );
foreach ( object attribute in attributes )

    GPUShaderAttribute attr = ( GPUShaderAttribute ) attribute;
    if ( attr != null )
        return attr.GPUShader;

return 0;

另一个问题是,如果没有找到,我应该返回什么? 0 可以转换为任何枚举,对吧?这就是我退货的原因。

忘了说,上面的代码为每个枚举成员返回 0。

【问题讨论】:

What AttributeTarget should I use for enum members? 的可能重复项 不,这不一样。在这里,我只是尝试使用反射获取枚举成员上设置的自定义属性。 Getting attributes of Enum's value的可能重复 【参考方案1】:

尝试使用通用方法

属性:

class DayAttribute : Attribute

    public string Name  get; private set; 

    public DayAttribute(string name)
    
        this.Name = name;
    

枚举:

enum Days

    [Day("Saturday")]
    Sat,
    [Day("Sunday")]
    Sun,
    [Day("Monday")]
    Mon, 
    [Day("Tuesday")]
    Tue,
    [Day("Wednesday")]
    Wed,
    [Day("Thursday")]
    Thu, 
    [Day("Friday")]
    Fri

通用方法:

        public static TAttribute GetAttribute<TAttribute>(this Enum value)
        where TAttribute : Attribute
    
        var enumType = value.GetType();
        var name = Enum.GetName(enumType, value);
        return enumType.GetField(name).GetCustomAttributes(false).OfType<TAttribute>().SingleOrDefault();
    

调用:

        static void Main(string[] args)
    
        var day = Days.Mon;
        Console.WriteLine(day.GetAttribute<DayAttribute>().Name);
        Console.ReadLine();
    

结果:

星期一

【讨论】:

希望我能给这个答案投票 100 次!!好东西:-) 是的,可以工作.. 但如果您没有为特定的枚举值声明属性,您可能会在 null 上调用 .Name。即您应该在调用 .Name 之前检查 day.GetAttribute() != null 【参考方案2】:

做你想做的事情有点乱,因为你必须使用反射:

public GPUShaderAttribute GetGPUShader(EffectType effectType)

    MemberInfo memberInfo = typeof(EffectType).GetMember(effectType.ToString())
                                              .FirstOrDefault();

    if (memberInfo != null)
    
        GPUShaderAttribute attribute = (GPUShaderAttribute) 
                     memberInfo.GetCustomAttributes(typeof(GPUShaderAttribute), false)
                               .FirstOrDefault();
        return attribute;
    

    return null;

这将返回GPUShaderAttribute 的一个实例,该实例与EffectType 的枚举值上标记的实例相关。您必须在 EffectType 枚举的特定值上调用它:

GPUShaderAttribute attribute = GetGPUShader(EffectType.MyEffect);

一旦您拥有属性的实例,您就可以从中获取特定的值,这些值标记在各个枚举值上。

【讨论】:

谢谢,它的工作原理。我不知道会这么复杂。但这是最简单的方法,对吧?你也知道为什么我的版本不起作用。我认为由于无法实例化枚举,因此使用 enum.getCustomAttributes 会起作用。 @Joan:据我所知,这是最简单的方法。您的方法不起作用,因为您获取的是在枚举类型而不是类型的值上定义的属性。 谢谢阿德里安,现在说得通了。【参考方案3】:

还有另一种使用泛型的方法:

public static T GetAttribute<T>(Enum enumValue) where T: Attribute

    T attribute;

    MemberInfo memberInfo = enumValue.GetType().GetMember(enumValue.ToString())
                                    .FirstOrDefault();

    if (memberInfo != null)
    
        attribute = (T) memberInfo.GetCustomAttributes(typeof (T), false).FirstOrDefault();
        return attribute;
    
    return null;

【讨论】:

我喜欢这个,但它没有考虑到同一属性有多个实例的可能性。我拿走了你所拥有的并将其修改为使用 T[] 而不是 T,然后删除了 GetCustomAttributes 上的 FirstOrDefault()。【参考方案4】:

假设GPUShaderAttribute

[AttributeUsage(AttributeTargets.Field,AllowMultiple =false)]
public class GPUShaderAttribute: Attribute

    public GPUShaderAttribute(string value)
    
        Value = value;
    
    public string Value  get; internal set; 

然后我们可以编写一些通用方法来返回枚举值和GPUShaderAttribute 对象的字典。

    /// <summary>
    /// returns the attribute for a given enum
    /// </summary>        
    public static TAttribute GetAttribute<TAttribute>(IConvertible @enum)
    
        TAttribute attributeValue = default(TAttribute);
        if (@enum != null)
        
            FieldInfo fi = @enum.GetType().GetField(@enum.ToString());
            attributeValue = fi == null ? attributeValue : (TAttribute)fi.GetCustomAttributes(typeof(TAttribute), false).DefaultIfEmpty(null).FirstOrDefault();

        
        return attributeValue;
    

然后用这个方法返回整个集合。

/// <summary>
/// Returns a dictionary of all the Enum fields with the attribute.
/// </summary>
public static Dictionary<Enum, RAttribute> GetEnumObjReference<TEnum, RAttribute>()

    Dictionary<Enum, RAttribute> _dict = new Dictionary<Enum, RAttribute>();
    Type enumType = typeof(TEnum);
    Type enumUnderlyingType = Enum.GetUnderlyingType(enumType);
    Array enumValues = Enum.GetValues(enumType);
    foreach (Enum enumValue in enumValues)
    
        _dict.Add(enumValue, GetAttribute<RAttribute>(enumValue));
    

    return _dict;

如果你只是想要一个字符串值,我会推荐一个稍微不同的路线。

    /// <summary>
    /// Returns the string value of the custom attribute property requested.
    /// </summary>
    public static string GetAttributeValue<TAttribute>(IConvertible @enum, string propertyName = "Value")
    
        TAttribute attribute = GetAttribute<TAttribute>(@enum);
        return attribute == null ? null : attribute.GetType().GetProperty(propertyName).GetValue(attribute).ToString();

    

    /// <summary>
    /// Returns a dictionary of all the Enum fields with the string of the property from the custom attribute nulls default to the enumName
    /// </summary>
    public static Dictionary<Enum, string> GetEnumStringReference<TEnum, RAttribute>(string propertyName = "Value")
    
        Dictionary<Enum, string> _dict = new Dictionary<Enum, string>();
        Type enumType = typeof(TEnum);
        Type enumUnderlyingType = Enum.GetUnderlyingType(enumType);
        Array enumValues = Enum.GetValues(enumType);
        foreach (Enum enumValue in enumValues)
        
            string enumName = Enum.GetName(typeof(TEnum), enumValue);
            string decoratorValue = Common.GetAttributeValue<RAttribute>(enumValue, propertyName) ?? enumName;
            _dict.Add(enumValue, decoratorValue);
        

        return _dict;
    

【讨论】:

【参考方案5】:

我想出了一种不同的方法来定位目标枚举值的 FieldInfo 元素。通过将枚举值转换为字符串来定位枚举值感觉不对,所以我选择使用 LINQ 检查字段列表:

Type enumType = value.GetType();
FieldInfo[] fields = enumType.GetFields();
FieldInfo fi = fields.Where(tField =>
    tField.IsLiteral &&
    tField.GetValue(null).Equals(value)
    ).First();

所以我所有的都发光了:

    public static TAttribute GetAttribute<TAttribute>(this Enum value) 
        where TAttribute : Attribute
    

        Type enumType = value.GetType();
        FieldInfo[] fields = enumType.GetFields();
        FieldInfo fi = fields.Where(tField =>
            tField.IsLiteral &&
            tField.GetValue(null).Equals(value)
            ).First();

        // If we didn't get, return null
        if (fi == null) return null;

        // We found the element (which we always should in an enum)
        // return the attribute if it exists.
        return (TAttribute)(fi.GetCustomAttribute(typeof(TAttribute)));
    

【讨论】:

这是一个非常干净的通用解决方案。效果很好!【参考方案6】:
public string GetEnumAttributeValue(Enum enumValue, Type attributeType, string attributePropertyName)
        
            /* New generic version (GetEnumDescriptionAttribute results can be achieved using this new GetEnumAttribute with a call like (enumValue, typeof(DescriptionAttribute), "Description")
             * Extracts a given attribute value from an enum:
             *
             * Ex:
             * public enum X
             * 
                     [MyAttribute(myProp = "aaaa")]
             *       x1,
             *       x2,
             *       [Description("desc")]
             *       x3
             * 
             *
             * Usage:
             *      GetEnumAttribute(X.x1, typeof(MyAttribute), "myProp") returns "aaaa"
             *      GetEnumAttribute(X.x2, typeof(MyAttribute), "myProp") returns string.Empty
             *      GetEnumAttribute(X.x3, typeof(DescriptionAttribute), "Description") returns "desc"
             */

            var attributeObj = enumValue.GetType()?.GetMember(enumValue.ToString())?.FirstOrDefault()?.GetCustomAttributes(attributeType, false)?.FirstOrDefault();

            if (attributeObj == null)
                return string.Empty;
            else
            
                try
                
                    var attributeCastedObj = Convert.ChangeType(attributeObj, attributeType);
                    var attributePropertyValue = attributeType.GetProperty(attributePropertyName)?.GetValue(attributeCastedObj);
                    return attributePropertyValue?.ToString() ?? string.Empty;
                
                catch (Exception ex)
                
                    return string.Empty;
                
            
        

【讨论】:

以上是关于如何获取枚举的自定义属性值?的主要内容,如果未能解决你的问题,请参考以下文章

任何人都知道快速获取枚举值的自定义属性的方法吗?

任何人都知道快速获取枚举值的自定义属性的方法吗?

如何从自定义用户控件 WPF、C# 中的枚举自定义属性中获取值?

如何在 ASP.Net MVC 5 视图中获取 ApplicationUser 的自定义属性值?

一段简单的代码记录如何通过 js 给 HTML 设置自定义属性,并且通过点击事件获取到所设置的自定义属性值

vue怎么获取option的自定义属性