Existe uma maneira de testar se T herda / implementa uma classe / interface?
private void MyGenericClass<T> ()
{
if(T ... inherits or implements some class/interface
}
Existe uma maneira de testar se T herda / implementa uma classe / interface?
private void MyGenericClass<T> ()
{
if(T ... inherits or implements some class/interface
}
Respostas:
Existe um método chamado Type.IsAssignableFrom () .
Para verificar se T
herda / implementa Employee
:
typeof(Employee).IsAssignableFrom(typeof(T));
Se você está direcionando o .NET Core, o método mudou para TypeInfo:
typeof(Employee).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())
T inherits U
realmente se traduz em typeof(T).IsAssignableFrom(typeof(U))
.
T
for restrito a algum outro tipo TOther
, então quando executado, typeof(T)
irá realmente avaliar typeof(TOther)
e não qualquer tipo que T
você realmente passou e, nesse caso, typeof(SomeInterface).IsAssignableFrom(typeof(T))
irá falhar (assumindo TOther
que também não implementa SomeInterface
), mesmo que seu tipo de concreto tenha implementado SomeInterface
.
IsAssignableFrom
da TypeInfo
classe só aceita TypeInfo como seu único argumento, então o exemplo deve ser o seguinte:typeof(Employee).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())
Você pode usar restrições na classe.
MyClass<T> where T : Employee
Dê uma olhada em http://msdn.microsoft.com/en-us/library/d5x73970.aspx
Se você quiser verificar durante a compilação: Erro se se T
NÃO implementar a interface / classe desejada, você pode usar a seguinte restrição
public void MyRestrictedMethod<T>() where T : MyInterface1, MyInterface2, MySuperClass
{
//Code of my method here, clean without any check for type constraints.
}
Espero que ajude.
A sintaxe correta é
typeof(Employee).IsAssignableFrom(typeof(T))
Valor de retorno:
true
sec
e o atualType
representam o mesmo tipo, ou se o atualType
está na hierarquia de herança dec
, ou se o atualType
é uminterface
quec
implementa, ou sec
é um parâmetro de tipo genérico e o atualType
representa uma das restrições dec
, ou ifc
representa um tipo de valor e o atualType
representaNullable<c>
(Nullable(Of c)
no Visual Basic).false
se nenhuma dessas condições fortrue
, ou sec
fornull
.
Se Employee IsAssignableFrom T
então T
herda de Employee
.
O uso
typeof(T).IsAssignableFrom(typeof(Employee))
true
só retorna quando
T
e Employee
representam o mesmo tipo; ou,Employee
herda de T
.Este pode ser o uso pretendido em alguns casos, mas para a pergunta original (e o uso mais comum), para determinar quando T
herda ou implementa algum class
/ interface
, use:
typeof(Employee).IsAssignableFrom(typeof(T))
O que todos realmente querem dizer é:
typeof(BaseType).IsAssignableFrom(typeof(DerivedType)) // => true
porque você pode literalmente atribuir de uma instância de a DerivedType
a uma instância de 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 alguns exemplos concretos se você estiver tendo problemas para entender:
(via LinqPad, daí o 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 básica-> classe básica
Verdade
child1-> baseclass
Falso
classe básica-> filho1
Verdade
child2-> baseclass
Falso
classe básica-> filho2
Verdade
nobase-> baseclass
Falso
classe básica-> nobase
Falso
e
- FALHA: c1 = b1
- b1 = c1
- FALHA: c2 = b1
- b1 = c2
Embora IsAssignableFrom seja a melhor maneira como outros declararam, se você só precisar verificar se uma classe herda de outra, typeof(T).BaseType == typeof(SomeClass)
isso também funcionará.
SomeClass
não seja diretamente derivado de BaseClass
.
Maneiras alternativas de saber se um objeto o
herda uma classe ou implementa uma interface é usar os operadores is
e as
.
Se você quiser saber apenas se um objeto herda uma classe ou implementa uma interface, o is
operador retornará um resultado booleano:
bool isCompatibleType = (o is BaseType || o is IInterface);
Se você quiser usar a classe herdada ou a interface implementada após o teste, o as
operador executará uma conversão segura, retornando uma referência à classe herdada ou à interface implementada se compatível ou nula se não for compatível:
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 você tiver apenas o tipo T
, use a resposta de @nikeee.