How to get Custom Attribute values for enums?

前端 未结 6 1497
独厮守ぢ
独厮守ぢ 2020-12-05 12:45

I have an enum where each member has a custom attribute applied to it. How can I retrieve the value stored in each attribute?

Right now I do this:

va         


        
相关标签:
6条回答
  • 2020-12-05 13:18

    There is another method to do this with generics:

    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;
    }
    
    0 讨论(0)
  • 2020-12-05 13:23

    It is a bit messy to do what you are trying to do as you have to use reflection:

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

    This will return an instance of the GPUShaderAttribute that is relevant to the one marked up on the enum value of EffectType. You have to call it on a specific value of the EffectType enum:

    GPUShaderAttribute attribute = GetGPUShader(EffectType.MyEffect);
    

    Once you have the instance of the attribute, you can get the specific values out of it that are marked-up on the individual enum values.

    0 讨论(0)
  • 2020-12-05 13:26
    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;
                    }
                }
            }
    
    0 讨论(0)
  • 2020-12-05 13:29

    Try using a generic method

    Attribute:

    class DayAttribute : Attribute
    {
        public string Name { get; private set; }
    
        public DayAttribute(string name)
        {
            this.Name = name;
        }
    }
    

    Enum:

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

    Generic method:

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

    Invoke:

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

    Result:

    Monday

    0 讨论(0)
  • 2020-12-05 13:34

    I came up with a different method to locate the FieldInfo element for the targeted enumerated value. Locating the enumerated value by converting it to a string felt wrong, so I opted for checking the field list with LINQ:

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

    So all glommed together I have:

        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)));
        }
    
    0 讨论(0)
  • 2020-12-05 13:35

    Assuming GPUShaderAttribute:

    [AttributeUsage(AttributeTargets.Field,AllowMultiple =false)]
    public class GPUShaderAttribute: Attribute
    {
        public GPUShaderAttribute(string value)
        {
            Value = value;
        }
        public string Value { get; internal set; }
    }
    

    Then we could write a few generic methods to return a dictionary of the enum values and the GPUShaderAttribute object.

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

    Then return the whole set with this method.

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

    If you just wanted a string value I would recommend a slightly different route.

        /// <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;
        }
    
    0 讨论(0)
提交回复
热议问题