Überprüfen Sie, ob 'T' eine Klasse / Schnittstelle erbt oder implementiert

92

Gibt es eine Möglichkeit zu testen, ob T eine Klasse / Schnittstelle erbt / implementiert?

private void MyGenericClass<T> ()
{
    if(T ... inherits or implements some class/interface
}
user1229895
quelle
4
Dies scheint zu funktionieren ... Wenn (typeof (TestClass) .IsAssignableFrom (typeof (T))), könnte jemand meinen Verdacht bestätigen? Vielen Dank!
user1229895
Ich bin mir absolut sicher, dass diese Antwort viele Male dupliziert wird!
Felix K.
3
Felix K Auch wenn diese Antwort viele Male dupliziert wurde, hilft sie auch vielen Leuten oft;) ... wie ich vor fünf Minuten :)
Samuel

Antworten:

136

Es gibt eine Methode namens Type.IsAssignableFrom () .

So überprüfen Sie, ob Terbt / implementiert Employee:

typeof(Employee).IsAssignableFrom(typeof(T));

Wenn Sie auf .NET Core abzielen, wurde die Methode nach TypeInfo verschoben:

typeof(Employee).GetTypeInfo().IsAssignableFrom(typeof(T).Ge‌​tTypeInfo())
Nikeee
quelle
Sie sollten Ihre Antwort mit einem Beispiel aktualisieren, z. B. typeof (T) .IsAssignableFrom (typeof (IMyInterface))
Dr. Andrew Burnett-Thompson
Nicht gemacht Nikeee; Die alte Antwort ist immer noch da. :) Ich habe ein paar Sekunden gebraucht, um herauszufinden, was los ist. Auf jeden Fall +1, wieder eine nette Funktion des .net-Frameworks.
Samuel
In der Tat ist die Art, wie Sie es erwähnen, die Art, wie ich es vor einiger Zeit hatte. Ich habe das korrigiert. Siehe vorherige Kommentare. T inherits Uübersetzt tatsächlich zu typeof(T).IsAssignableFrom(typeof(U)).
Nikeee
2
Während dies fast funktioniert, gibt es ein Problem, bei dem, wenn Tes auf einen anderen Typ beschränkt ist TOther, bei der Ausführung typeof(T)tatsächlich der typeof(TOther)Typ ausgewertet wird und nicht der Typ, den TSie tatsächlich übergeben haben, und in diesem Fall typeof(SomeInterface).IsAssignableFrom(typeof(T))fehlschlägt (vorausgesetzt TOther, nicht implementiert SomeInterface). obwohl Ihr konkreter Typ implementiert hat SomeInterface.
Dave Cousineau
1
In .net akzeptiert der Kern IsAssignableFromder TypeInfoKlasse nur TypeInfo als einziges Argument, daher sollte das Beispiel das folgende sein:typeof(Employee).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())
Bis zum
16

Wenn Sie während der Kompilierung überprüfen möchten: Fehler, wenn die gewünschte Schnittstelle / Klasse T NICHT implementiert wird, können Sie die folgende Einschränkung verwenden

public void MyRestrictedMethod<T>() where T : MyInterface1, MyInterface2, MySuperClass
{
    //Code of my method here, clean without any check for type constraints.
}

Ich hoffe das hilft.

Snajahi
quelle
12

Die richtige Syntax lautet

typeof(Employee).IsAssignableFrom(typeof(T))

Dokumentation

Rückgabewert: true wenn , cund der Strom Typerepräsentiert den gleichen Typen ist , oder wenn der Strom Typeist in der Vererbungshierarchie c, oder wenn der Strom Typeist , interfacedass cWerkzeuge, oder wenn cein generischer Typ - Parameter und der Strom Typeist eine der Einschränkungen coder if crepräsentiert einen Werttyp und der aktuelle Typerepräsentiert Nullable<c>( Nullable(Of c)in Visual Basic). falsewenn keine dieser Bedingungen erfüllt trueist oder wenn dies der Fall cist null.

Quelle

Erläuterung

Wenn Employee IsAssignableFrom Tdann Terbt von Employee.

Die Verwendung

typeof(T).IsAssignableFrom(typeof(Employee)) 

Gibt true nur zurück, wenn einer der beiden

  1. Tund Employeerepräsentieren den gleichen Typ; oder,
  2. Employeeerbt von T.

Dies kann in einigen Fällen eine beabsichtigte Verwendung sein , aber für die ursprüngliche Frage (und die häufigere Verwendung), um zu bestimmen, wann Teinige class/ geerbt oder implementiert werden interface, verwenden Sie:

typeof(Employee).IsAssignableFrom(typeof(T))
Luke
quelle
9

Was jeder wirklich meint ist:

typeof(BaseType).IsAssignableFrom(typeof(DerivedType)) // => true

weil Sie buchstäblich von einer Instanz von a DerivedTypezu einer Instanz von a zuweisen können BaseType:

DerivedType childInstance = new DerivedType();
BaseType parentInstance = childInstance; // okay, assigning base from derived
childInstance = (DerivedType) parentInstance; // not okay, assigning derived from base

wann

public class BaseType {}
public class DerivedType : BaseType {}

Und einige konkrete Beispiele, wenn Sie Probleme haben, Ihren Kopf darum zu wickeln:

(über LinqPad, daher das HorizontalRunund Dump)

void Main()
{
    // http://stackoverflow.com/questions/10718364/check-if-t-inherits-or-implements-a-class-interface

    var b1 = new BaseClass1();

    var c1 = new ChildClass1();
    var c2 = new ChildClass2();
    var nb = new nobase();

    Util.HorizontalRun(
        "baseclass->baseclass,child1->baseclass,baseclass->child1,child2->baseclass,baseclass->child2,nobase->baseclass,baseclass->nobase",
        b1.IsAssignableFrom(typeof(BaseClass1)),
        c1.IsAssignableFrom(typeof(BaseClass1)),
        b1.IsAssignableFrom(typeof(ChildClass1)),
        c2.IsAssignableFrom(typeof(BaseClass1)),
        b1.IsAssignableFrom(typeof(ChildClass2)),
        nb.IsAssignableFrom(typeof(BaseClass1)),
        b1.IsAssignableFrom(typeof(nobase))
        ).Dump("Results");

    var results = new List<string>();
    string test;

    test = "c1 = b1";
    try {
        c1 = (ChildClass1) b1;
        results.Add(test);
    } catch { results.Add("FAIL: " + test); }

    test = "b1 = c1";
    try {
        b1 = c1;
        results.Add(test);
    } catch { results.Add("FAIL: " + test); }

    test = "c2 = b1";
    try {
        c2 = (ChildClass2) b1;
        results.Add(test);
    } catch { results.Add("FAIL: " + test); }

    test = "b1 = c2";
    try {
        b1 = c2;
        results.Add(test);
    } catch { results.Add("FAIL: " + test); }

    results.Dump();
}

// Define other methods and classes here
public static class exts {
    public static bool IsAssignableFrom<T>(this T entity, Type baseType) {
        return typeof(T).IsAssignableFrom(baseType);
    }
}


class BaseClass1 {
    public int id;
}

class ChildClass1 : BaseClass1 {
    public string name;
}

class ChildClass2 : ChildClass1 {
    public string descr;
}

class nobase {
    public int id;
    public string name;
    public string descr;
}

Ergebnisse

Grundklasse-> Grundklasse

Wahr

child1-> Grundklasse

Falsch

Grundklasse-> Kind1

Wahr

child2-> Grundklasse

Falsch

Grundklasse-> Kind2

Wahr

nobase-> baseclass

Falsch

Grundklasse-> Nobase

Falsch

und

  • FEHLER: c1 = b1
  • b1 = c1
  • FEHLER: c2 = b1
  • b1 = c2
drzaus
quelle
2

Ich glaube, die Syntax lautet: typeof(Employee).IsAssignableFrom(typeof(T));

Kreidig
quelle
Dies ist die beabsichtigte Syntax. +1
Luke
0

Obwohl IsAssignableFrom der beste Weg ist, wie andere angegeben haben, typeof(T).BaseType == typeof(SomeClass)erledigt der Job auch , wenn Sie nur überprüfen müssen, ob eine Klasse von einer anderen erbt .

Jed
quelle
Das funktioniert, es SomeClasssei denn, es ist nicht direkt abgeleitet von BaseClass.
Suncat2000
0

Alternative Möglichkeiten, um festzustellen, ob ein Objekt oeine Klasse erbt oder eine Schnittstelle implementiert, sind die Operatoren isund as.

Wenn Sie nur wissen möchten, ob ein Objekt eine Klasse erbt oder eine Schnittstelle implementiert, gibt der isOperator ein boolesches Ergebnis zurück:

bool isCompatibleType = (o is BaseType || o is IInterface);

Wenn Sie die geerbte Klasse oder die implementierte Schnittstelle nach Ihrem Test verwenden möchten, führt der asOperator eine sichere Umwandlung durch und gibt einen Verweis auf die geerbte Klasse oder die implementierte Schnittstelle zurück, falls kompatibel, oder null, wenn nicht kompatibel:

BaseType b = o as BaseType; // Null if d does not inherit from BaseType.

IInterface i = o as IInterface; // Null if d does not implement IInterface.

Wenn Sie nur den Typ haben T, verwenden Sie die Antwort von @ nikeee.

Suncat2000
quelle