Як отримати список властивостей із заданим атрибутом?


210

У мене є тип, tі я хотів би отримати список публічних властивостей, які мають атрибут MyAttribute. Атрибут позначений AllowMultiple = falseтаким чином:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]

На даний момент у мене це, але я думаю, що є кращий спосіб:

foreach (PropertyInfo prop in t.GetProperties())
{
    object[] attributes = prop.GetCustomAttributes(typeof(MyAttribute), true);
    if (attributes.Length == 1)
    {
         //Property with my custom attribute
    }
}

Як я можу це покращити? Мої вибачення, якщо це дублікат, там є нитка рефлексійних тем ... здається, це досить гаряча тема.


Ні. Вам потрібен PropertyInfo, перш ніж ви зможете з’ясувати, чи є у властивості атрибут.
Ганс Пасант

Відповіді:


391
var props = t.GetProperties().Where(
                prop => Attribute.IsDefined(prop, typeof(MyAttribute)));

Це дозволяє уникнути необхідності матеріалізувати будь-які екземпляри атрибутів (тобто це дешевше, ніж GetCustomAttribute[s]().


1
Гарна пропозиція. Однак мені знадобиться екземпляр атрибута, але він мені подобається.
wsanville

1
Я просто шукав спосіб перевірити існування атрибута без побічного ефекту, який викликає властивість. Дякую Марку, це працює!
Örjan Jämte

1
@ ÖrjanJämte властивість getне викликається навіть при використанні GetCustomAttributes; однак атрибут інстанціюється , що не є вільним. Якщо вам не потрібно перевіряти конкретні значення атрибута, IsDefinedце дешевше. А в 4.5 є способи перевірити дані про дані, не створюючи фактично жодних примірників атрибутів (хоча це призначено лише для дуже конкретних сценаріїв)
Марк Гравелл


2
для ядра dotnet: var props = t.GetProperties (). Де (e => e.IsDefined (typeof (MyAttribute)));
Rtype

45

Рішення, яке я в основному використовую, базується на відповіді Томаша Петрикека. Зазвичай я хочу щось робити і з атрибутом, і з властивістю.

var props = from p in this.GetType().GetProperties()
            let attr = p.GetCustomAttributes(typeof(MyAttribute), true)
            where attr.Length == 1
            select new { Property = p, Attribute = attr.First() as MyAttribute};

+1 - "Я, як правило, хочу щось робити і з атрибутом, і з властивістю" - це те, що я шукав - велике спасибі за повідомлення про вашу відповідь!
Явар Муртаза

34

Наскільки я знаю, немає кращого способу щодо розумнішої роботи з бібліотекою Reflection. Однак ви можете використовувати LINQ, щоб зробити код трохи приємнішим:

var props = from p in t.GetProperties()
            let attrs = p.GetCustomAttributes(typeof(MyAttribute), true)
            where attrs.Length != 0 select p;

// Do something with the properties in 'props'

Я вважаю, що це допомагає тобі структурувати код у більш читабельному вигляді.


13

Завжди є LINQ:

t.GetProperties().Where(
    p=>p.GetCustomAttributes(typeof(MyAttribute), true).Length != 0)

6

Якщо ви регулярно маєте справу з атрибутами у відображенні, визначити деякі методи розширення дуже, дуже практично. Ви побачите, що в багатьох проектах там. Цей у мене часто такий:

public static bool HasAttribute<T>(this ICustomAttributeProvider provider) where T : Attribute
{
  var atts = provider.GetCustomAttributes(typeof(T), true);
  return atts.Length > 0;
}

якими ви можете користуватися як typeof(Foo).HasAttribute<BarAttribute>();

Інші проекти (наприклад, StructureMap) мають повноцінні класи ReflectionHelper, які використовують дерева Expression, щоб мати тонкий синтаксис ідентичності, наприклад PropertyInfos. Потім використання виглядає так:

ReflectionHelper.GetProperty<Foo>(x => x.MyProperty).HasAttribute<BarAttribute>()

2

На додаток до попередніх відповідей: краще використовувати метод Any()замість перевірки довжини колекції:

propertiesWithMyAttribute = type.GetProperties()
  .Where(x => x.GetCustomAttributes(typeof(MyAttribute), true).Any());

Приклад на dotnetfiddle: https://dotnetfiddle.net/96mKep


@ cogumel0 Перш за все, .Any()не перевірте довжину. Але моя відповідь була не про знайдені властивості з точно одним атрибутом. По-друге, я не впевнений, що ви правильно прочитали код - .Anyметод, викликаний за результатом GetCustomAttrubutesметоду. Отже типом propertiesWithMyAttributeзаповіту буде сукупність властивостей. Ознайомтеся з прикладом у dotnetfiddle (я додаю посилання на відповідь).
платник

1
Ви можете замінити. Де б не було. Так, оскільки .Any також дозволяє лямбда.
PRMan
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.