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
}
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
}
Réponses:
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).GetTypeInfo())
T inherits U
se traduit en fait par typeof(T).IsAssignableFrom(typeof(U))
.
T
est 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 T
vous avez réellement passé, et dans ce cas, typeof(SomeInterface).IsAssignableFrom(typeof(T))
échouera (en supposant qu'il TOther
ne soit pas également implémenté SomeInterface
), même si votre type de béton a été implémenté SomeInterface
.
IsAssignableFrom
de la TypeInfo
classe n'accepte que TypeInfo comme seul argument, donc l'exemple doit être le suivant:typeof(Employee).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())
Vous pouvez utiliser des contraintes sur la classe.
MyClass<T> where T : Employee
Jetez un œil à http://msdn.microsoft.com/en-us/library/d5x73970.aspx
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.
La syntaxe correcte est
typeof(Employee).IsAssignableFrom(typeof(T))
Valeur de retour:
true
sic
et le courantType
représentent le même type, ou si le courantType
est dans la hiérarchie d'héritage dec
, ou si le courantType
est uninterface
quic
implémente, ou sic
est un paramètre de type générique et le courantType
représente l'une des contraintes dec
, ou ifc
représente un type valeur et le courantType
représenteNullable<c>
(Nullable(Of c)
dans Visual Basic).false
si aucune de ces conditions ne l'esttrue
, ou si elle l'c
estnull
.
Si Employee IsAssignableFrom T
alors T
hérite de Employee
.
L'usage
typeof(T).IsAssignableFrom(typeof(Employee))
retourne true
uniquement lorsque soit
T
et Employee
représentent le même type; ou,Employee
hé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 T
hérite ou implémente certains class
/ interface
, utilisez:
typeof(Employee).IsAssignableFrom(typeof(T))
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 HorizontalRun
et 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;
}
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
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.
SomeClass
ne soit directement dérivé de BaseClass
.
Une autre façon de savoir si un objet o
hérite d'une classe ou implémente une interface consiste à utiliser les opérateurs is
et as
.
Si vous voulez savoir uniquement si un objet hérite d'une classe ou implémente une interface, l' is
opé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' as
opé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.