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.