Frage basierend auf MSDN-Beispiel .
Angenommen, wir haben einige C # -Klassen mit HelpAttribute in einer eigenständigen Desktopanwendung. Ist es möglich, alle Klassen mit einem solchen Attribut aufzulisten? Ist es sinnvoll, Klassen so zu erkennen? Ein benutzerdefiniertes Attribut wird verwendet, um mögliche Menüoptionen aufzulisten. Wenn Sie ein Element auswählen, wird die Instanz einer solchen Klasse auf dem Bildschirm angezeigt. Die Anzahl der Klassen / Gegenstände wird langsam zunehmen, aber auf diese Weise können wir vermeiden, sie alle an anderer Stelle aufzuzählen, denke ich.
Select
Erweiterungsmethode geschrieben , und der Compiler generiert eine Zustandsmaschine genau so, als ob SieSelect
aufgrund Ihrer Verwendung von aufgerufen hättenyield return
. Schließlich alle Performance - Gewinne , die möglicherweise in der Mehrzahl der Fälle sein Mikro-Optimierungen erzielt werden.Nun, Sie müssten alle Klassen in allen Assemblys auflisten, die in die aktuelle App-Domäne geladen werden. Dazu rufen Sie die
GetAssemblies
Methode auf derAppDomain
Instanz für die aktuelle App-Domäne auf.Von dort aus würden Sie
GetExportedTypes
(wenn Sie nur öffentliche Typen möchten) oderGetTypes
auf jedemAssembly
die Typen aufrufen , die in der Assembly enthalten sind.Anschließend rufen Sie die
GetCustomAttributes
Erweiterungsmethode für jedeType
Instanz auf und übergeben den Typ des Attributs, das Sie suchen möchten.Sie können LINQ verwenden, um dies für Sie zu vereinfachen:
Mit der obigen Abfrage erhalten Sie jeden Typ, auf den Ihr Attribut angewendet wurde, sowie die Instanz der ihm zugewiesenen Attribute.
Beachten Sie, dass dieser Vorgang teuer sein kann, wenn Sie eine große Anzahl von Assemblys in Ihre Anwendungsdomäne geladen haben. Sie können Parallel LINQ verwenden , um die Operationszeit wie folgt zu verkürzen:
Das Filtern nach einem bestimmten
Assembly
ist einfach:Wenn die Assembly eine große Anzahl von Typen enthält, können Sie Parallel LINQ erneut verwenden:
quelle
Andere Antworten verweisen auf GetCustomAttributes . Hinzufügen dieses Beispiels für die Verwendung von IsDefined
quelle
Wie bereits erwähnt, ist Reflexion der richtige Weg. Wenn Sie dies häufig aufrufen, empfehle ich dringend, die Ergebnisse zwischenzuspeichern, da die Reflexion, insbesondere die Aufzählung in jeder Klasse, sehr langsam sein kann.
Dies ist ein Ausschnitt aus meinem Code, der alle Typen in allen geladenen Assemblys durchläuft:
quelle
Dies ist eine Leistungssteigerung zusätzlich zu der akzeptierten Lösung. Das Iterieren, obwohl alle Klassen langsam sein können, weil es so viele gibt. Manchmal können Sie eine gesamte Baugruppe herausfiltern, ohne einen ihrer Typen zu betrachten.
Wenn Sie beispielsweise nach einem Attribut suchen, das Sie selbst deklariert haben, erwarten Sie nicht, dass eine der System-DLLs Typen mit diesem Attribut enthält. Mit der Assembly.GlobalAssemblyCache-Eigenschaft können Sie schnell nach System-DLLs suchen. Als ich dies mit einem echten Programm versuchte, stellte ich fest, dass ich 30.101 Typen überspringen konnte und nur 1.983 Typen überprüfen muss.
Eine andere Möglichkeit zum Filtern ist die Verwendung von Assembly.ReferencedAssemblies. Wenn Sie Klassen mit einem bestimmten Attribut möchten und dieses Attribut in einer bestimmten Assembly definiert ist, interessieren Sie sich vermutlich nur für diese Assembly und andere Assemblys, die darauf verweisen. In meinen Tests hat dies etwas mehr geholfen als das Überprüfen der GlobalAssemblyCache-Eigenschaft.
Ich habe beide kombiniert und es noch schneller bekommen. Der folgende Code enthält beide Filter.
quelle
Im Fall der Einschränkungen für Portable .NET sollte der folgende Code funktionieren:
oder für eine große Anzahl von Assemblys, die den Schleifenstatus verwenden
yield return
:quelle
Wir können Andrews Antwort verbessern und das Ganze in eine LINQ-Abfrage umwandeln.
quelle