Получить атрибут из Enum, зная только PropertyInfo - PullRequest
1 голос
/ 01 июля 2019

Что у меня есть:

У меня есть класс, где многие свойства используют атрибут определенного типа. Этот класс также содержит свойство, являющееся перечисляемым значением, допускающим значение NULL, и каждое значение перечисления также может быть украшено одним и тем же атрибутом. Например:

// My basic class
public class Upgrade
{
    [Abbreviation("name")]
    public int string Name { get; set; }

    [Abbreviation("opt")]
    public bool Optional { get; set; } = true;

    [Abbreviation("type")]
    public UpgradeType? TypeOfUpgrade { get; set; } = null;
}

// My basic enum
public enum UpgradeType
{
    [Abbreviation("fl")]
    Full, 

    [Abbreviation("prt")]
    Partial
}

// My basic attribute
public class AbbreviationAttribute: Attribute 
{
    public string Value{ get; private set; }

    public AbbreviationAttribute(string value)
    {
        Value = value;
    }
}

Что я пытаюсь сделать:

Я пытаюсь получить имя каждого свойства и его значение. Однако, если свойство украшено AbbreviationAttribute, вместо него следует использовать значение из атрибута. Аналогично, если свойство имеет тип любого перечисления , значение должно быть взято из перечисления AbbreviationAttribute, если оно есть.

Итак, для такого объекта, как этот:

Upgrade upgrade = new Upgrade 
{
    Name = "First Upgrade",
    Optional = false,
    TypeOfUpgrade = UpgradeType.Full
};

Я хотел бы вывести строку:

name = First Upgrade; opt = false; type = fl

Как мне этого добиться?

Что я пробовал:

Я могу получить атрибут из свойства, однако я не уверен, как получить к нему доступ из свойства enum. Таким образом, в приведенном выше примере я могу получить AbbreviationAttribute из свойства TypeOfUpgrade, но, поскольку это enum, мне нужно получить AbbreviationAttribute из его значения.

string values = string.Empty;
// foreach property
foreach(PropertyInfo pi in this.GetType().GetProperties())
{
    // get the attribute from the property, if it exists
    AbbreviationAttribute attr = pi.GetCustomAttribute<AbbreviationAttribute>();

    if (attr != null)
    {
        //append the value from the attribute, instead of the property name
        values += $"{attr.Value}=";

        // if property is an enum (nullable or otherwise)
        if (pi.PropertyType.IsEnum || pi.PropertyType.IsNullableEnum())
        {
            // get the type of enum
            Type type = Nullable.GetUnderlyingType(pi.PropertyType);
            if (type == null)
            {
                type = pi.PropertyType;
            }

            // --------------------------
            // Now I have the type of enum, and the value from the PropertyInfo,
            // how can I access the AbbreviationAttribute that's on the enum's value? 

        }
    }
}

// helper method
public static bool IsNullableEnum(this Type t)
{
    Type u = Nullable.GetUnderlyingType(t);
    return (u != null) && u.IsEnum;
}

1 Ответ

0 голосов
/ 01 июля 2019

Значение enum является статическим полем типа enum.

Таким образом, когда у вас есть значение enum, вы получите Type для типа enum, получите информацию о поле для значения enum и получите атрибут из информации об элементе.

public static TAttributeType GetEnumValueAttribute<TAttributeType>(Enum val) 
    where TAttributeType : Attribute
{
    if (val == null)
    {
        return null;
    }

    return 
        val.GetType().
        GetMember(val.ToString())?.
        FirstOrDefault()?.
        GetCustomAttribute<TAttributeType>();
}

И в вашем цикле:

foreach (PropertyInfo pi in obj.GetType().GetProperties())
{
    // get the attribute from the property, if it exists
    AbbreviationAttribute attr = pi.GetCustomAttribute<AbbreviationAttribute>();

    if (attr != null)
    {
        //append the value from the attribute, instead of the property name
        values += $"{attr.Value}=";

        // if property is an enum (nullable or otherwise)
        if (pi.PropertyType.IsEnum || pi.PropertyType.IsNullableEnum())
        {
            values += $"{GetEnumValueAttribute<AbbreviationAttribute>((Enum)pi.GetValue(obj))?.Value};";
        }
        else
        {
            values += $"{pi.GetValue(obj)};";
        }
    }
}

Вы действительно задаете дубликат этого вопроса .Я скопировал его код, но немного его модернизировал.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...