Vérifier si 'T' hérite ou implémente une classe / interface

92

Existe-t-il un moyen de tester si T hérite / implémente une classe / interface?

private void MyGenericClass<T> ()
{
    if(T ... inherits or implements some class/interface
}
user1229895
la source
4
cela semble fonctionner ... si (typeof (TestClass) .IsAssignableFrom (typeof (T))), quelqu'un pourrait-il confirmer mes soupçons? Merci!
user1229895
Je suis absolument sûr que cette réponse est répétée plusieurs fois!
Felix K.
3
Felix K Même si cette réponse a été répétée plusieurs fois, elle aide aussi beaucoup de gars à plusieurs reprises;) ... comme moi il y a cinq minutes :)
Samuel

Réponses:

136

Il existe une méthode appelée Type.IsAssignableFrom () .

Pour vérifier si Thérite / implémente Employee:

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

Si vous ciblez .NET Core, la méthode a été déplacée vers TypeInfo:

typeof(Employee).GetTypeInfo().IsAssignableFrom(typeof(T).Ge‌​tTypeInfo())
nikeee
la source
vous devriez mettre à jour votre réponse avec un exemple, par exemple typeof (T) .IsAssignableFrom (typeof (IMyInterface))
Dr. Andrew Burnett-Thompson
Pas fait nikeee; la vieille réponse est toujours là. :) J'ai pris quelques secondes pour comprendre ce qui ne va pas. En tout cas, +1, une nouvelle fonctionnalité intéressante du framework .net.
Samuel
En fait, la façon dont vous parlez est la façon dont je l'avais fait il y a quelque temps. J'ai corrigé celui-ci. Voir les commentaires précédents. T inherits Use traduit en fait par typeof(T).IsAssignableFrom(typeof(U)).
nikeee
3
Bien que cela fonctionne presque, il y a un problème où if Test contraint à un autre type TOther, puis lorsqu'il est exécuté, il typeof(T)sera en fait évalué à typeof(TOther)et non au type que Tvous avez réellement passé, et dans ce cas, typeof(SomeInterface).IsAssignableFrom(typeof(T))échouera (en supposant qu'il TOtherne soit pas également implémenté SomeInterface), même si votre type de béton a été implémenté SomeInterface.
Dave Cousineau
1
Dans .net, le noyau IsAssignableFromde la TypeInfoclasse n'accepte que TypeInfo comme seul argument, donc l'exemple doit être le suivant:typeof(Employee).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())
To Ka
16

Si vous souhaitez vérifier lors de la compilation: Erreur si si T n'implémente PAS l'interface / la classe souhaitée, vous pouvez utiliser la contrainte suivante

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

J'espère que cela aide.

Snajahi
la source
12

La syntaxe correcte est

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

Documentation

Valeur de retour: true si cet le courant Typereprésentent le même type, ou si le courant Typeest dans la hiérarchie d'héritage de c, ou si le courant Typeest un interfacequi cimplémente, ou si cest un paramètre de type générique et le courant Typereprésente l'une des contraintes de c, ou if creprésente un type valeur et le courant Typereprésente Nullable<c>( Nullable(Of c)dans Visual Basic). falsesi aucune de ces conditions ne l'est true, ou si elle l' cest null.

la source

Explication

Si Employee IsAssignableFrom Talors Thérite de Employee.

L'usage

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

retourne true uniquement lorsque soit

  1. Tet Employeereprésentent le même type; ou,
  2. Employeehérite de T.

Cela peut être une utilisation prévue dans certains cas, mais pour la question d'origine (et l'utilisation la plus courante), pour déterminer quand Thérite ou implémente certains class/ interface, utilisez:

typeof(Employee).IsAssignableFrom(typeof(T))
Luke
la source
9

Ce que tout le monde veut vraiment dire, c'est:

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

car vous pouvez littéralement attribuer d' une instance de a DerivedTypeà une instance de a BaseType:

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

quand

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

Et quelques exemples concrets si vous avez du mal à vous y mettre la tête:

(via LinqPad, d'où le HorizontalRunet 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;
}

Résultats

baseclass-> baseclass

Vrai

child1-> baseclass

Faux

baseclass-> enfant1

Vrai

child2-> baseclass

Faux

baseclass-> enfant2

Vrai

nobase-> baseclass

Faux

baseclass-> nobase

Faux

et

  • ÉCHEC: c1 = b1
  • b1 = c1
  • ÉCHEC: c2 = b1
  • b1 = c2
drzaus
la source
2

Je pense que la syntaxe est: typeof(Employee).IsAssignableFrom(typeof(T));

Crayeux
la source
C'est la syntaxe prévue. +1
Luke
0

Bien que IsAssignableFrom soit le meilleur moyen, comme d'autres l'ont indiqué, si vous avez seulement besoin de vérifier si une classe hérite d'une autre, typeof(T).BaseType == typeof(SomeClass)fait également le travail.

Jed
la source
Cela fonctionne à moins qu'il SomeClassne soit directement dérivé de BaseClass.
Suncat2000
0

Une autre façon de savoir si un objet ohérite d'une classe ou implémente une interface consiste à utiliser les opérateurs iset as.

Si vous voulez savoir uniquement si un objet hérite d'une classe ou implémente une interface, l' isopérateur renverra un résultat booléen:

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

Si vous souhaitez utiliser la classe héritée ou l'interface implémentée après votre test, l' asopérateur effectuera un cast sécurisé, renvoyant une référence à la classe héritée ou à l'interface implémentée si compatible ou null si non compatible:

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.

Si vous n'avez que le type T, utilisez la réponse de @ nikeee.

Suncat2000
la source