Jak uzyskać listę właściwości o danym atrybucie?


210

Mam typ ti chciałbym uzyskać listę właściwości publicznych, które mają atrybut MyAttribute. Atrybut jest oznaczony AllowMultiple = falsenastępująco:

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

Obecnie mam to, ale myślę, że jest lepszy sposób:

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

Jak mogę to poprawić? Przepraszam, jeśli to duplikat, jest mnóstwo wątków refleksyjnych ... wydaje się, że to dość gorący temat.


Nie. Potrzebujesz PropertyInfo, aby dowiedzieć się, czy właściwość ma atrybut.
Hans Passant

Odpowiedzi:


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

Pozwala to uniknąć konieczności materializacji wystąpień atrybutów (tzn. Jest tańszy niż GetCustomAttribute[s]().


1
Dobry pomysł. Potrzebuję jednak instancji atrybutu, ale mi się podoba.
wsanville

1
Właśnie szukałem sposobu, aby sprawdzić istnienie atrybutu bez wywoływanego efektu ubocznego wywołanego przez właściwość. Dzięki Marc, to działa!
Örjan Jämte

1
@ ÖrjanJämte właściwość getnie jest wywoływana nawet podczas używania GetCustomAttributes; jednak atrybut jest tworzony w postaci instancji , co nie jest darmowe. Jeśli nie musisz sprawdzać określonych wartości atrybutu, IsDefinedjest tańszy. A w 4.5 istnieją sposoby sprawdzania danych instancji bez faktycznego tworzenia instancji atrybutów (chociaż jest to przeznaczone tylko dla bardzo specyficznych scenariuszy)
Marc Gravell


2
dla dotnet core: var props = t.GetProperties (). Where (e => e.IsDefined (typeof (MyAttribute)));
Rtype

45

Rozwiązanie, z którego najczęściej korzystam, oparte jest na odpowiedzi Tomasa Petricka. I zazwyczaj chcą coś zrobić z obu atrybutu i mienia.

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 - „Zwykle chcę zrobić coś z atrybutem i właściwością”, tego szukałem - wielkie dzięki za opublikowanie twojej odpowiedzi!
Yawar Murtaza

34

O ile mi wiadomo, nie ma lepszego sposobu na mądrzejszą pracę z biblioteką Reflection. Możesz jednak użyć LINQ, aby kod był nieco ładniejszy:

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'

Uważam, że pomaga to uporządkować kod w bardziej czytelny sposób.


13

Zawsze jest LINQ:

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

6

Jeśli regularnie zajmujesz się atrybutami w odbiciu, zdefiniowanie niektórych metod rozszerzenia jest bardzo, bardzo praktyczne. Zobaczysz to w wielu projektach. Ten tutaj jest tym, który często mam:

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

którego możesz użyć jak typeof(Foo).HasAttribute<BarAttribute>();

Inne projekty (np. StructureMap) mają pełnoprawne klasy ReflectionHelper, które wykorzystują drzewa wyrażeń, aby mieć dokładną składnię tożsamości, np. PropertyInfos. Użycie wygląda następująco:

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

2

Oprócz poprzednich odpowiedzi: lepiej użyć metody Any()zamiast sprawdzania długości kolekcji:

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

Przykład w dotnetfiddle: https://dotnetfiddle.net/96mKep


@ cogumel0 Przede wszystkim na pewno .Any()nie sprawdza długości. Ale moja odpowiedź nie dotyczyła znalezionych właściwości z dokładnie jednym atrybutem. Po drugie, nie jestem pewien, czy poprawnie odczytałeś kod - .Anymetoda wywołana na wyniku GetCustomAttrubutesmetody. Tak więc typem propertiesWithMyAttributebędzie kolekcja właściwości. Sprawdź przykład w dotnetfiddle (dodaję link do odpowiedzi).
osoba pobierająca opłaty

1
Możesz zastąpić .Gdzie z .Dowolny, ponieważ .Dowolny również zezwala na lambdas.
PRMan
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.