Как получить список членов перечисления, которые были украшены атрибутом Speci c - PullRequest
1 голос
/ 03 мая 2020

Я хочу вернуть список членов перечисления, которые имеют атрибут c. Так что для примера кода я хотел бы список с перечислениями SecondValue и ThirdValue, но не FirstValue или FourthValue, потому что он не имеет атрибута Container.

Как я могу это сделать?

PS: раньше это было помечено как дубликат со ссылкой на это: Получение атрибутов значения Enum

Это НЕ тот же вопрос. Я сделал больше примеров кода, чтобы сделать мой вопрос более понятным. См. Определение функции и что она должна возвращать.

    [AttributeUsage(AttributeTargets.Field)]
    public sealed class ContainerAttribute : Attribute
    {
        public string Name { get; }

        public ContainerAttribute(string name)
        {
            Name = name;
        }
    }

    public enum MyEnum
    {
        [SomeOtherAttribute("attr")]
        FirstValue,

        [Container("name1")]
        SecondValue,

        [Container("name1")]
        ThirdValue,

        FourthValue
    }

    public List<MyEnum> GetEnumsWithAttribute(Attribute value) { }

    public void Main(String[] args) { 
       // someEnums should return list with content: [MyEnum.SecondValue, MyEnum.ThirdValue];
       var someEnums = GetEnumsWithAttribute(ContainerAttribute);
    }

Ответы [ 2 ]

3 голосов
/ 03 мая 2020

Каждый раз, когда вы работаете с Атрибутами, вам придется использовать Reflection. Смешайте немного Linq, и вы сможете проверить поля вашего перечисления для фильтрации по атрибуту Type, а затем проанализировать результаты по имени поля.

Type ta = typeof(ContainerAttribute);
Type t = typeof(MyEnum);

var result = t.GetFields()
    .Where(a => a.CustomAttributes.Any(c => c.AttributeType == ta))
    .Select(a => (MyEnum)Enum.Parse(t, a.Name))
    .ToList();

Update

Пока из вашего вопроса неясно, если вам потребуется дополнительная фильтрация по Name, ответ Гуру подразумевает, что, возможно, вы это сделаете или сделаете в будущем. Если это так, вы можете отредактировать мое решение, изменив предложение Where так, чтобы оно приняло строку, которую вы хотите Name:

// method would take a string argument rather than hard-coding "name1"
.Where(a => a.CustomAttributes.Any(c => c.AttributeType == ta && c.ConstructorArguments.Any(ca => ca.Value.ToString() == "name1")))
2 голосов
/ 03 мая 2020

Для этого можно использовать отражение :

public static List<MyEnum> GetEnumsWithAttribute(Attribute value)
    {
        return typeof(MyEnum)
           .GetMembers()
           .Where(m => m.MemberType == MemberTypes.Field)
           .Where(m => m.GetCustomAttributes().Any(a => a.Equals(value)))
           .Select(m => Enum.Parse<MyEnum>(m.Name))
           .ToList();
    }

Эта реализация опирается на .Equals, перегруженную в ContainerAttribute, например:

public override bool Equals(object? obj)
        {
            var other = obj as ContainerAttribute;
            if (other == null) return false;
            return this.Name == other.Name;
        }

Если вы не хотите переопределять Equals, вы можете изменить свой метод на общий c:

    public static List<MyEnum> GetEnumsWithAttribute<T>(T value, Func<T, T , bool> comparerFunc) where T: Attribute
    {
        return typeof(MyEnum)
           .GetMembers()
           .Where(m => m.MemberType == MemberTypes.Field)
           .Where(m => m.GetCustomAttributes().Any(a => a is T && comparerFunc((T)a, value)))
           .Select(m => Enum.Parse<MyEnum>(m.Name))
           .ToList();
    }

И использование:

var someEnums = GetEnumsWithAttribute(new ContainerAttribute("name1"), (a1, a2) => a1.Name == a2.Name);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...