Как получить значения пользовательских атрибутов для перечислений? - PullRequest
37 голосов
/ 24 февраля 2011

У меня есть enum, где к каждому члену применен пользовательский атрибут.Как я могу получить значение, хранящееся в каждом атрибуте?

Прямо сейчас я делаю это:

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 для каждого члена enum.

Ответы [ 6 ]

34 голосов
/ 27 января 2016

Попробуйте использовать универсальный метод

Атрибут:

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
}

Общий метод:

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

Результат:

понедельник

34 голосов
/ 24 февраля 2011

Делать то, что вы пытаетесь сделать, немного грязно, так как вы должны использовать отражение:

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, который относится к размеченномуна значение enum EffectType.Вы должны вызывать его для определенного значения перечисления EffectType:

GPUShaderAttribute attribute = GetGPUShader(EffectType.MyEffect);

Получив экземпляр атрибута, вы можете получить из него конкретные значения, размеченные наиндивидуальные значения перечисления.

24 голосов
/ 27 октября 2012

Есть еще один способ сделать это с помощью дженериков:

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;
}
2 голосов
/ 23 августа 2018

Предполагая 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;
    }
2 голосов
/ 24 февраля 2011

Я не пробовал этого, но похоже, что этот пост описывает, что вы ищете: Справка по атрибуту перечисления

0 голосов
/ 12 апреля 2019

Я придумал другой метод, чтобы найти элемент 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)));
    }
...