Controlla se "T" eredita o implementa una classe / interfaccia


92

C'è un modo per verificare se T eredita / implementa una classe / interfaccia?

private void MyGenericClass<T> ()
{
    if(T ... inherits or implements some class/interface
}

4
questo sembra funzionare ... se (typeof (TestClass) .IsAssignableFrom (typeof (T))), qualcuno potrebbe confermare i miei sospetti? Grazie!
user1229895

Sono assolutamente sicuro che questa risposta sia ripetuta molte volte!
Felix K.

3
Felix K Anche se questa risposta è stata ripetuta molte volte, aiuta anche molti ragazzi molte volte;) ... come me cinque minuti fa :)
Samuel

Risposte:


136

C'è un metodo chiamato Type.IsAssignableFrom () .

Per verificare se Teredita / implementa Employee:

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

Se stai prendendo di mira .NET Core, il metodo è stato spostato in TypeInfo:

typeof(Employee).GetTypeInfo().IsAssignableFrom(typeof(T).Ge‌​tTypeInfo())

dovresti aggiornare la tua risposta con un esempio, ad esempio typeof (T) .IsAssignableFrom (typeof (IMyInterface))
Dr. Andrew Burnett-Thompson,

Non fatto nikeee; la vecchia risposta è ancora lì. :) Ho impiegato un paio di secondi per capire cosa c'è che non va. In ogni caso, +1, ancora una volta bella caratteristica del framework .net.
Samuel

In effetti, il modo in cui parli è il modo in cui l'avevo io qualche tempo fa. Ho corretto questo. Vedi i commenti precedenti. T inherits Usi traduce effettivamente in typeof(T).IsAssignableFrom(typeof(U)).
nikeee

2
Anche se questo funziona quasi, c'è un problema in cui if Tè vincolato a qualche altro tipo TOther, quindi quando viene eseguito, typeof(T)valuterà effettivamente typeof(TOther)e non qualunque tipo Ttu abbia effettivamente passato, e in quel caso typeof(SomeInterface).IsAssignableFrom(typeof(T))fallirà (supponendo TOtherche non lo implementa anche SomeInterface), anche se il tuo tipo concreto ha implementato SomeInterface.
Dave Cousineau,

1
In .net core IsAssignableFromdella TypeInfoclasse accetta solo TypeInfo come unico argomento, quindi l'esempio dovrebbe essere il seguente:typeof(Employee).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())
To Ka


16

Se si desidera controllare durante la compilazione: Errore se T NON implementa l'interfaccia / classe desiderata, è possibile utilizzare il seguente vincolo

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

Spero che aiuti.


12

La sintassi corretta è

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

Documentazione

Valore di ritorno: true se ce la corrente Typerappresentano lo stesso tipo, o se la corrente Typeè nella gerarchia di ereditarietà di c, o se la corrente Typeè una interfaceche cimplementa, o se cè un parametro di tipo generico e la corrente Typerappresenta uno dei vincoli di c, o se crappresenta un tipo di valore e la corrente Typerappresenta Nullable<c>( Nullable(Of c)in Visual Basic). falsese nessuna di queste condizioni è presente trueo se lo cè null.

fonte

Spiegazione

Se Employee IsAssignableFrom Tpoi Teredita da Employee.

L'utilizzo

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

ritorna true solo quando uno dei due

  1. Te Employeerappresentano lo stesso tipo; o,
  2. Employeeeredita da T.

Questo può essere un uso previsto in alcuni casi, ma per la domanda originale (e l'uso più comune), per determinare quando Teredita o implementa alcune class/ interface, usa:

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

9

Quello che tutti vogliono veramente dire è:

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

perché puoi letteralmente assegnare da un'istanza di a DerivedTypea un'istanza di a BaseType:

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

quando

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

E alcuni esempi concreti se hai problemi a capirlo:

(tramite LinqPad, da cui HorizontalRune 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;
}

Risultati

classe base-> classe base

Vero

child1-> baseclass

Falso

classe base-> figlio1

Vero

child2-> baseclass

Falso

classe base-> figlio2

Vero

nobase-> baseclass

Falso

baseclass-> nobase

Falso

e

  • FAIL: c1 = b1
  • b1 = c1
  • FAIL: c2 = b1
  • b1 = c2

2

Credo che la sintassi sia: typeof(Employee).IsAssignableFrom(typeof(T));


Questa è la sintassi prevista. +1
Luca

0

Sebbene IsAssignableFrom sia il modo migliore come altri hanno affermato, se hai solo bisogno di controllare se una classe eredita da un'altra, typeof(T).BaseType == typeof(SomeClass)fa anche il lavoro.


Funziona a meno che SomeClassnon sia derivato direttamente da BaseClass.
Suncat2000

0

Un modo alternativo per sapere se un oggetto oeredita una classe o implementa un'interfaccia consiste nell'usare gli operatori ise as.

Se vuoi solo sapere se un oggetto eredita una classe o implementa un'interfaccia, l' isoperatore restituirà un risultato booleano:

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

Se si desidera utilizzare la classe ereditata o l'interfaccia implementata dopo il test, l' asoperatore eseguirà un cast sicuro, restituendo un riferimento alla classe ereditata o all'interfaccia implementata se compatibile o null se non compatibile:

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.

Se hai solo il tipo T, usa la risposta di @ nikeee.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.