Ich habe eine generische Klasse in meinem Projekt mit abgeleiteten Klassen.
public class GenericClass<T> : GenericInterface<T>
{
}
public class Test : GenericClass<SomeType>
{
}
Gibt es eine Möglichkeit herauszufinden, ob ein Type
Objekt abgeleitet ist GenericClass
?
t.IsSubclassOf(typeof(GenericClass<>))
funktioniert nicht.
c#
generics
reflection
bernhardrusch
quelle
quelle
(Neu veröffentlicht aufgrund eines massiven Umschreibens)
Die Code-Antwort von JaredPar ist fantastisch, aber ich habe einen Tipp, der es unnötig machen würde, wenn Ihre generischen Typen nicht auf Werttypparametern basieren. Ich war gespannt, warum der "is" -Operator nicht funktionieren würde, deshalb habe ich auch die Ergebnisse meiner Experimente als zukünftige Referenz dokumentiert. Bitte verbessern Sie diese Antwort, um ihre Klarheit weiter zu verbessern.
TRINKGELD:
Wenn Sie sicherstellen, dass Ihre GenericClass-Implementierung von einer abstrakten nicht generischen Basisklasse wie GenericClassBase erbt, können Sie dieselbe Frage ohne Probleme wie folgt stellen:
IsSubclassOf ()
Meine Tests haben ergeben, dass IsSubclassOf () bei parameterlosen generischen Typen wie z
während es mit funktioniert
Daher funktioniert der folgende Code für jede Ableitung von GenericClass <>, vorausgesetzt, Sie sind bereit, basierend auf SomeType zu testen:
Ich kann mir nur vorstellen, dass Sie mit GenericClass <> testen möchten, und zwar in einem Plug-in-Framework-Szenario.
Gedanken zum Operator "ist"
Zur Entwurfszeit erlaubt C # die Verwendung parameterloser Generika nicht, da sie zu diesem Zeitpunkt im Wesentlichen kein vollständiger CLR-Typ sind. Daher müssen Sie generische Variablen mit Parametern deklarieren. Aus diesem Grund ist der Operator "is" für die Arbeit mit Objekten so leistungsfähig. Im Übrigen kann der Operator "is" auch keine parameterlosen generischen Typen auswerten.
Der Operator "is" testet die gesamte Vererbungskette einschließlich der Schnittstellen.
Bei einer Instanz eines Objekts reicht die folgende Methode aus:
Das ist irgendwie überflüssig, aber ich dachte mir, ich würde es für alle visualisieren.
Gegeben
Die folgenden Codezeilen würden true zurückgeben:
Wenn Sie jedoch etwas Spezifisches für GenericClass möchten, können Sie es vermutlich spezifischer gestalten:
Dann würden Sie so testen:
quelle
Type
Objekt haben.typeof
Operator. In den Dokumenten heißt es: "Der Operator typeof wird verwendet, um das System.Type-Objekt für einen Typ abzurufen."Ich habe einige dieser Proben durchgearbeitet und festgestellt, dass sie in einigen Fällen fehlten. Diese Version funktioniert mit allen Arten von Generika: Typen, Schnittstellen und Typdefinitionen davon.
Hier sind auch die Unit-Tests:
quelle
!parent.IsGenericType || parent.GetGenericTypeDefinition() == parent;
Sie ersetzen diese Variable also durch die Erweiterung der if-Anweisung:if (parent.IsGenericType && shouldUseGenericType)
und Sie erhaltenif (parent.IsGenericType && (!parent.IsGenericType || parent.GetGenericTypeDefinition() == parent))
diese , die sich dann aufif (parent.IsGenericType && parent.GetGenericTypeDefinition() == parent)) parent = parent.GetGenericTypeDefinition();
int j = 0;
if (j is an int && j == 0)
{ j=0; }
bekomme ich meine Referenz gleich und Wert gleich verwechselt? Ich dachte, es gibt nur eine Instanz jedes Typs im Speicher, also zeigen zwei Variablen, die auf denselben Typ verweisen, tatsächlich auf denselben Speicherort im Speicher.Es scheint mir, dass diese Implementierung in mehreren Fällen funktioniert (generische Klasse und Schnittstelle mit oder ohne initiierte Parameter, unabhängig von der Anzahl der untergeordneten Parameter und Parameter):
Hier sind meine
7076 Testfälle:Klassen und Schnittstellen zum Testen:
quelle
Der Code von JaredPar funktioniert jedoch nur für eine Vererbungsstufe. Verwenden Sie für unbegrenzte Vererbungsstufen den folgenden Code
quelle
while
Code in JaredPar deckt unbegrenzte Ebenen ab.Hier ist eine kleine Methode, die ich erstellt habe, um zu überprüfen, ob ein Objekt von einem bestimmten Typ abgeleitet ist. Funktioniert super für mich!
quelle
Es könnte übertrieben sein, aber ich verwende Erweiterungsmethoden wie die folgenden. Sie prüfen Schnittstellen sowie Unterklassen. Es kann auch den Typ zurückgeben, der die angegebene generische Definition hat.
Zum Beispiel für das Beispiel in der Frage kann es sowohl gegen die generische Schnittstelle als auch gegen die generische Klasse getestet werden. Der zurückgegebene Typ kann verwendet werden, um
GetGenericArguments
zu bestimmen, dass der generische Argumenttyp "SomeType" ist.quelle
Aufbauend auf der hervorragenden Antwort von fir3rpho3nixx und David Schmitt habe ich ihren Code geändert und den ShouldInheritOrImplementTypedGenericInterface-Test (letzter) hinzugefügt.
quelle
Dies kann alles einfach mit linq gemacht werden. Dadurch werden alle Typen gefunden, die eine Unterklasse der generischen Basisklasse GenericBaseType sind.
quelle
Einfache Lösung: Erstellen Sie einfach eine zweite, nicht generische Schnittstelle und fügen Sie sie der generischen Klasse hinzu:
Dann sind Sie nur für die in irgendeiner Weise Sie gerne mit
is
,as
,IsAssignableFrom
etc.Natürlich nur möglich, wenn Sie die Möglichkeit haben, die generische Klasse zu bearbeiten (die das OP zu haben scheint), aber es ist etwas eleganter und lesbarer als die Verwendung einer kryptischen Erweiterungsmethode.
quelle
IGenericClass
können Sie dies nicht garantierenGenericClass
oderGenericInterface
es wird tatsächlich erweitert oder implementiert. Dies bedeutet, dass Sie mit Ihrem Compiler auch nicht auf Mitglieder der generischen Klasse zugreifen können.Zur Antwort von @ jaredpar hinzugefügt, verwende ich Folgendes, um nach Schnittstellen zu suchen:
Ex:
quelle
JaredPar,
Dies hat bei mir nicht funktioniert, wenn ich typeof (type <>) als toCheck übergeben habe. Folgendes habe ich geändert.
quelle
typeof(type<>)
alstoCheck
. Außerdem benötigen Sie wirklich die Nullprüfung wie in der JaredPar-Lösung. Darüber hinaus weiß ich nicht, was Sie sonst noch erreichen, wenn Siecur == generic
seine Lösung durch einecur.IsGenericType && generic.GetGenericTypeDefinition() == cur.GetGenericTypeDefinition()
andere ersetzen, als Ihre Methode so einzuschränken, dass sie nur für generische Typen funktioniert. Mit anderen Worten, so etwas scheitert mit einer Ausnahme:IsSubclassOfRawGeneric(typeof(MyClass), typeof(MyClass<>))
@EnocNRoll - Die Antwort von Ananda Gopal ist interessant, aber falls eine Instanz nicht vorher instanziiert wurde oder Sie mit einer generischen Typdefinition überprüfen möchten, würde ich diese Methode vorschlagen:
und benutze es wie:
Es gibt vier bedingte Fälle , in denen beide
t
(zu prüfendem) undd
sind generische Typen und zwei Fälle werden durch abgedecktt==d
denen (1) wedert
nochd
ist eine allgemeine Definition oder (2) beide von ihnen sind allgemeine Definitionen . Die übrigen Fälle sind einer von ihnen ist eine generische Definition. Nur wennd
es sich bereits um eine generische Definition handelt, haben wir die Möglichkeit zu sagen, dass a einet
ist,d
aber nicht umgekehrt.Es sollte mit beliebigen Klassen oder Schnittstellen funktionieren, die Sie testen möchten, und gibt zurück, als ob Sie eine Instanz dieses Typs mit dem
is
Operator testen würden .quelle
quelle
Sie können diese Erweiterung ausprobieren
quelle
Spät zum Spiel ... Ich habe auch noch eine weitere Permutation von JarodPars Antwort.
Hier ist Type.IsSubClassOf (Type) mit freundlicher Genehmigung des Reflektors:
Daraus sehen wir, dass es nichts zu Cray Cray macht und dem iterativen Ansatz von JaredPar ähnlich ist. So weit, ist es gut. Hier ist meine Version (Haftungsausschluss: nicht gründlich getestet, also lass es mich wissen, wenn du Probleme findest)
Im Grunde ist dies nur eine Erweiterungsmethode für System.Type. Ich habe dies getan, um den Typ "thisType" absichtlich auf konkrete Typen zu beschränken, da ich sofort die LINQ-Abfrage "where" als Prädikate für Typobjekte verwende. Ich bin sicher, alle klugen Leute da draußen könnten es auf eine effiziente statische Allzweckmethode reduzieren, wenn Sie müssen :) Der Code macht ein paar Dinge, die der Code der Antwort nicht tut
Der Rest ist im Grunde der gleiche wie der Code von JaredPar
quelle