Wie kann ich mithilfe von Reflection alle Typen ermitteln, die eine Schnittstelle mit C # 3.0 / .NET 3.5 mit dem geringsten Code implementieren und Iterationen minimieren?
Folgendes möchte ich neu schreiben:
foreach (Type t in this.GetType().Assembly.GetTypes())
if (t is IMyInterface)
; //do stuff
Antworten:
Meins wäre das in c # 3.0 :)
Grundsätzlich ist die geringste Anzahl von Iterationen immer:
quelle
.Where(p => type.IsAssignableFrom(p) && !p.IsInterface);
, um sie herauszufiltern (oderp.IsClass
).List<string>
nicht implementiert,IEnumerable<object>
aber diese Methode gibt in .Net 4.0 aufgrund der tatsächlich falschen Kovarianz true zurück. Die richtige Antwort ist hier.Where(p => type.IsAssignableFrom(p) && p.IsClass && !p.IsAbstract
Das hat bei mir funktioniert. Es durchläuft die Klassen und prüft, ob sie von myInterface abgeleitet sind
quelle
So finden Sie alle Typen in einer Assembly, die die IFoo-Schnittstelle implementieren:
Beachten Sie, dass der Vorschlag von Ryan Rinaldi falsch war. Es werden 0 Typen zurückgegeben. Du kannst nicht schreiben
weil type eine System.Type-Instanz ist und niemals vom Typ IFoo sein wird. Stattdessen überprüfen Sie, ob IFoo vom Typ zuweisbar ist. Das wird Ihre erwarteten Ergebnisse erhalten.
Auch der Vorschlag von Adam Wright, der derzeit als Antwort markiert ist, ist aus demselben Grund ebenfalls falsch. Zur Laufzeit werden 0 Typen zurückgegeben, da alle System.Type-Instanzen keine IFoo-Implementierer waren.
quelle
Ich schätze, dass dies eine sehr alte Frage ist, aber ich dachte, ich würde eine weitere Antwort für zukünftige Benutzer hinzufügen, da alle bisherigen Antworten irgendeine Form von verwenden
Assembly.GetTypes
.GetTypes () gibt zwar alle Typen zurück, bedeutet jedoch nicht unbedingt, dass Sie sie aktivieren und somit möglicherweise a auslösen können
ReflectionTypeLoadException
.Ein klassisches Beispiel dafür, dass ein Typ nicht aktiviert werden kann, ist, wenn der zurückgegebene Typ
derived
von stammt,base
aberbase
in einer anderen Assembly als der vonderived
einer Assembly definiert ist, auf die die aufrufende Assembly nicht verweist.Sagen wir also, wir haben:
Wenn in
ClassC
wasAssemblyC
drin ist, dann tun wir etwas gemäß der akzeptierten Antwort:Dann wird es ein werfen
ReflectionTypeLoadException
.Dies liegt daran, dass Sie ohne einen Verweis auf
AssemblyA
inAssemblyC
nicht in der Lage wären:Mit anderen Worten
ClassB
ist nicht ladbar das ist etwas, dass der Aufruf von GetTypes Kontrollen und wirft auf.Um die Ergebnismenge sicher für ladbare Typen zu qualifizieren, führen Sie stattdessen gemäß diesem Phil Haacked- Artikel Get All Types in a Assembly und Jon Skeet-Code Folgendes aus :
Und dann:
quelle
CreateInstance
für alle aktivieren , und es wurde eine Ausnahme ausgelöst, als versucht wurde, die eigentliche Schnittstelle zu erstellen (was mich eine Weile verwirrt hatte, als ich dachte, dass die eigentliche Schnittstelle in dieser Lösung nicht im Weg war). Also habe ich den Code in geändertGetLoadableTypes(assembly).Where(interfaceType.IsAssignableFrom).Where(t => !(t.Equals(interfaceType))).ToList();
.Andere Antworten hier verwenden
IsAssignableFrom
. Sie können auchFindInterfaces
aus demSystem
Namespace verwenden, wie hier beschrieben .Hier ist ein Beispiel, das alle Assemblys im Ordner der aktuell ausgeführten Assembly überprüft und nach Klassen sucht, die eine bestimmte Schnittstelle implementieren (wobei LINQ aus Gründen der Übersichtlichkeit vermieden wird).
Sie können eine Liste von Schnittstellen einrichten, wenn Sie mehr als eine übereinstimmen möchten.
quelle
Durchlaufen Sie alle geladenen Assemblys, durchlaufen Sie alle ihre Typen und prüfen Sie, ob sie die Schnittstelle implementieren.
etwas wie:
quelle
Dies hat bei mir funktioniert (wenn Sie möchten, können Sie Systemtypen in der Suche ausschließen):
quelle
Bearbeiten: Ich habe gerade die Bearbeitung gesehen, um zu verdeutlichen, dass die ursprüngliche Frage die Reduzierung von Iterationen / Code betraf und das alles gut und gut als Übung ist, aber in realen Situationen werden Sie unabhängig davon die schnellste Implementierung wünschen wie cool der zugrunde liegende LINQ aussieht.
Hier ist meine Utils-Methode zum Durchlaufen der geladenen Typen. Es behandelt sowohl reguläre Klassen als auch Schnittstellen, und die Option excludeSystemTypes beschleunigt die Arbeit erheblich, wenn Sie nach Implementierungen in Ihrer eigenen Codebasis / Drittanbieter-Codebasis suchen.
Es ist nicht schön, gebe ich zu.
quelle
excludeSystemTypes
zweimal in einemif
?Andere Antworten funktionierten nicht mit einer generischen Schnittstelle .
In diesem Fall ersetzen Sie einfach typeof (ISomeInterface) durch typeof (T).
Also mit
Wir bekommen alle Baugruppen
wird verwendet, um die Schnittstelle und abstrakte auszuschließen und
um sie in einer Liste zu haben.
quelle
Es gibt keine einfache Möglichkeit (in Bezug auf die Leistung), das zu tun, was Sie tun möchten.
Reflection funktioniert hauptsächlich mit Baugruppen und Typen, sodass Sie alle Baugruppentypen abrufen und nach der richtigen Schnittstelle abfragen müssen. Hier ist ein Beispiel:
Damit erhalten Sie alle Typen, die das IMyInterface in der Assembly MyAssembly implementieren
quelle
Noch besser bei der Auswahl des Montageorts. Filtern Sie die meisten Assemblys, wenn Sie wissen, dass sich alle implementierten Schnittstellen in derselben Assembly befinden. DefinedTypes.
Von Can Bilgin
quelle
Die OfType Linq-Methode kann genau für diese Art von Szenarien verwendet werden:
https://docs.microsoft.com/fr-fr/dotnet/api/system.linq.enumerable.oftype?view=netframework-4.8
quelle
Es gibt bereits viele gültige Antworten, aber ich möchte eine weitere Implementierung als Typerweiterung und eine Liste von Komponententests hinzufügen, um verschiedene Szenarien zu demonstrieren:
Dieser Algorithmus unterstützt die folgenden Szenarien:
quelle
quelle
Ich habe Ausnahmen im Linq-Code, also mache ich es so (ohne eine komplizierte Erweiterung):
quelle
Sie könnten etwas LINQ verwenden, um die Liste zu erhalten:
Aber ist das wirklich besser lesbar?
quelle