C'è un modo per verificare se T eredita / implementa una classe / interfaccia?
private void MyGenericClass<T> ()
{
if(T ... inherits or implements some class/interface
}
C'è un modo per verificare se T eredita / implementa una classe / interfaccia?
private void MyGenericClass<T> ()
{
if(T ... inherits or implements some class/interface
}
Risposte:
C'è un metodo chiamato Type.IsAssignableFrom () .
Per verificare se T
eredita / 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).GetTypeInfo())
T inherits U
si traduce effettivamente in typeof(T).IsAssignableFrom(typeof(U))
.
T
è vincolato a qualche altro tipo TOther
, quindi quando viene eseguito, typeof(T)
valuterà effettivamente typeof(TOther)
e non qualunque tipo T
tu abbia effettivamente passato, e in quel caso typeof(SomeInterface).IsAssignableFrom(typeof(T))
fallirà (supponendo TOther
che non lo implementa anche SomeInterface
), anche se il tuo tipo concreto ha implementato SomeInterface
.
IsAssignableFrom
della TypeInfo
classe accetta solo TypeInfo come unico argomento, quindi l'esempio dovrebbe essere il seguente:typeof(Employee).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())
È possibile utilizzare vincoli sulla classe.
MyClass<T> where T : Employee
Dai un'occhiata a http://msdn.microsoft.com/en-us/library/d5x73970.aspx
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.
La sintassi corretta è
typeof(Employee).IsAssignableFrom(typeof(T))
Valore di ritorno:
true
sec
e la correnteType
rappresentano lo stesso tipo, o se la correnteType
è nella gerarchia di ereditarietà dic
, o se la correnteType
è unainterface
chec
implementa, o sec
è un parametro di tipo generico e la correnteType
rappresenta uno dei vincoli dic
, o sec
rappresenta un tipo di valore e la correnteType
rappresentaNullable<c>
(Nullable(Of c)
in Visual Basic).false
se nessuna di queste condizioni è presentetrue
o se loc
ènull
.
Se Employee IsAssignableFrom T
poi T
eredita da Employee
.
L'utilizzo
typeof(T).IsAssignableFrom(typeof(Employee))
ritorna true
solo quando uno dei due
T
e Employee
rappresentano lo stesso tipo; o,Employee
eredita da T
.Questo può essere un uso previsto in alcuni casi, ma per la domanda originale (e l'uso più comune), per determinare quando T
eredita o implementa alcune class
/ interface
, usa:
typeof(Employee).IsAssignableFrom(typeof(T))
Quello che tutti vogliono veramente dire è:
typeof(BaseType).IsAssignableFrom(typeof(DerivedType)) // => true
perché puoi letteralmente assegnare da un'istanza di a DerivedType
a 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 HorizontalRun
e 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;
}
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
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.
SomeClass
non sia derivato direttamente da BaseClass
.
Un modo alternativo per sapere se un oggetto o
eredita una classe o implementa un'interfaccia consiste nell'usare gli operatori is
e as
.
Se vuoi solo sapere se un oggetto eredita una classe o implementa un'interfaccia, l' is
operatore 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' as
operatore 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.