Wie erhalte ich eine Liste von Eigenschaften mit einem bestimmten Attribut?


210

Ich habe einen Typ, t und möchte eine Liste der öffentlichen Eigenschaften erhalten, die das Attribut haben MyAttribute. Das Attribut ist AllowMultiple = falsewie folgt gekennzeichnet :

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

Momentan habe ich Folgendes, aber ich denke, es gibt einen besseren Weg:

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

Wie kann ich das verbessern? Ich entschuldige mich, wenn dies ein Duplikat ist, gibt es da draußen eine Menge Reflexionsfäden ... scheint ein ziemlich heißes Thema zu sein.


Nee. Sie benötigen eine PropertyInfo, bevor Sie herausfinden können, ob die Eigenschaft ein Attribut hat.
Hans Passant

Antworten:


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

Dadurch wird vermieden, dass Attributinstanzen materialisiert werden müssen (dh es ist billiger als GetCustomAttribute[s]().


1
Guter Vorschlag. Ich werde jedoch die Attributinstanz benötigen, aber es gefällt mir.
Wsanville

1
Ich habe nur nach einer Möglichkeit gesucht, die Existenz eines Attributs ohne den Nebeneffekt zu überprüfen, den die Eigenschaft aufruft. Danke Marc, es funktioniert!
Örjan Jämte

1
@ ÖrjanJämte die Eigenschaft getwird auch bei Verwendung nicht aufgerufen GetCustomAttributes; Das Attribut wird jedoch instanziiert , was nicht frei ist. Wenn Sie bestimmte Werte des Attributs nicht überprüfen müssen, IsDefinedist dies billiger. Und in 4.5 gibt es Möglichkeiten, die Instanziierungsdaten zu überprüfen, ohne tatsächlich Attributinstanzen zu erstellen (obwohl dies nur für sehr spezifische Szenarien vorgesehen ist)
Marc Gravell


2
für Dotnet-Kern: var props = t.GetProperties (). Where (e => e.IsDefined (typeof (MyAttribute)));
Rtype

45

Die Lösung, die ich am häufigsten verwende, basiert auf der Antwort von Tomas Petricek. Normalerweise möchte ich sowohl mit dem Attribut als auch mit der Eigenschaft etwas tun .

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 - "Ich möchte normalerweise sowohl mit dem Attribut als auch mit der Eigenschaft etwas tun" ist das, wonach ich gesucht habe - vielen Dank für die Veröffentlichung Ihrer Antwort!
Yawar Murtaza

34

Soweit ich weiß, gibt es keinen besseren Weg, um mit der Reflection-Bibliothek intelligenter zu arbeiten. Sie können jedoch LINQ verwenden, um den Code ein bisschen schöner zu machen:

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'

Ich glaube, dies hilft Ihnen, den Code besser lesbar zu strukturieren.


13

Es gibt immer LINQ:

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

6

Wenn Sie sich regelmäßig mit Attributen in Reflection beschäftigen, ist es sehr, sehr praktisch, einige Erweiterungsmethoden zu definieren. Sie werden das in vielen Projekten sehen. Dieser hier ist einer, den ich oft habe:

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

die du gerne benutzen kannst typeof(Foo).HasAttribute<BarAttribute>();

Andere Projekte (z. B. StructureMap) verfügen über vollwertige ReflectionHelper-Klassen, die Ausdrucksbäume verwenden, um eine feine Syntax für die Identität zu erhalten, z. B. PropertyInfos. Die Verwendung sieht dann so aus:

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

2

Zusätzlich zu den vorherigen Antworten: Es ist besser, die Methode zu verwenden, Any()anstatt die Länge der Sammlung zu überprüfen:

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

Das Beispiel bei dotnetfiddle: https://dotnetfiddle.net/96mKep


@ cogumel0 Zunächst einmal wird .Any()die Länge sicher nicht überprüft. Bei meiner Antwort ging es jedoch nicht um gefundene Eigenschaften mit genau einem Attribut. Zweitens bin ich mir nicht sicher, ob Sie den Code richtig gelesen haben - .AnyMethode, die für das Ergebnis der Methode aufgerufen GetCustomAttrubuteswird. Der Typ des propertiesWithMyAttributewird also die Sammlung der Eigenschaften sein. Schauen Sie sich das Beispiel bei dotnetfiddle an (ich füge den Link zur Antwort hinzu).
Feeeper

1
Sie können .Where durch .Any ersetzen, da .Any auch Lambdas zulässt.
PRMan
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.