108 votes

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

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
}

158voto

nikeee Points 2134

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

Pour vérifier si T hé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())

Notez que si vous voulez contraindre votre type T pour implémenter une interface ou hériter d'une classe, vous devriez opter pour la réponse de @snajahi, qui utilise des vérifications au moment de la compilation pour cela et ressemble génériquement à une meilleure approche de ce problème.

39voto

Sachin Kainth Points 7842

Vous pouvez utiliser des contraintes sur la classe.

MyClass<T> where T : Employee

Jetez un coup d'œil à http://msdn.microsoft.com/en-us/library/d5x73970.aspx

19voto

snajahi Points 851

Si vous voulez vérifier pendant la compilation : Erreur si si T n'a PAS mettre en œuvre l'interface/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 vous aidera.

13voto

Luke Willis Points 1833

La syntaxe correcte est

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

Documentation

Valeur de retour : true si c et le courant Type représentent le même type, ou si le Type se trouve dans la hiérarchie d'héritage de c ou si le courant Type est un interface que c met en œuvre, ou si c est un paramètre de type générique et la valeur actuelle de Type représente l'une des contraintes de c ou si c représente un type de valeur et la valeur courante Type représente Nullable<c> ( Nullable(Of c) en Visual Basic). false si aucune de ces conditions n'est true ou si c est null .

source

Explication

Si Employee IsAssignableFrom T puis T hérite de Employee .

L'usage

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

renvoie à true seulement lorsque soit

  1. T y Employee représentent le même type ; ou,
  2. Employee hérite de T .

Il peut s'agir d'un usage prévu dans un peu de mais pour la question originale (et l'usage le plus courant), pour déterminer quand T hérite ou implémente certains class / interface utiliser :

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

11voto

drzaus Points 3344

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

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

parce que vous pouvez littéralement affecter de une instance d'un DerivedType à une instance d'un 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 faire une idée :

(via LinqPad, d'où le HorizontalRun y 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

Véritable

enfant1->baseclasse

Faux

baseclass->child1

Véritable

enfant2->baseclasse

Faux

baseclass->child2

Véritable

nobase->baseclass

Faux

baseclass->nobase

Faux

et

  • ÉCHEC : c1 = b1
  • b1 = c1
  • ÉCHEC : c2 = b1
  • b1 = c2

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X