¿Hay alguna forma de probar si T hereda / implementa una clase / interfaz?
private void MyGenericClass<T> ()
{
if(T ... inherits or implements some class/interface
}
¿Hay alguna forma de probar si T hereda / implementa una clase / interfaz?
private void MyGenericClass<T> ()
{
if(T ... inherits or implements some class/interface
}
Respuestas:
Existe un método llamado Type.IsAssignableFrom () .
Para comprobar si T
hereda / implementa Employee
:
typeof(Employee).IsAssignableFrom(typeof(T));
Si tiene como destino .NET Core, el método se ha trasladado a TypeInfo:
typeof(Employee).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())
T inherits U
en realidad se traduce en typeof(T).IsAssignableFrom(typeof(U))
.
T
está restringido a algún otro tipo TOther
, luego, cuando se ejecuta, en typeof(T)
realidad se evaluará typeof(TOther)
y no en el tipo T
que haya pasado realmente, y en ese caso, typeof(SomeInterface).IsAssignableFrom(typeof(T))
fallará (suponiendo TOther
que no se implementa también SomeInterface
), a pesar de que su tipo concreto se implementó SomeInterface
.
IsAssignableFrom
de la TypeInfo
clase solo acepta TypeInfo como su único argumento, por lo que la muestra debe ser la siguiente:typeof(Employee).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())
Puede usar restricciones en la clase.
MyClass<T> where T : Employee
Eche un vistazo a http://msdn.microsoft.com/en-us/library/d5x73970.aspx
Si desea verificar durante la compilación: Error si T
NO implementa la interfaz / clase deseada, puede usar la siguiente restricción
public void MyRestrictedMethod<T>() where T : MyInterface1, MyInterface2, MySuperClass
{
//Code of my method here, clean without any check for type constraints.
}
Espero que eso ayude.
La sintaxis correcta es
typeof(Employee).IsAssignableFrom(typeof(T))
Valor de retorno:
true
sic
y el actualType
representan el mismo tipo, o si el actualType
está en la jerarquía de herencia dec
, o si el actualType
es uninterface
quec
implementa, o sic
es un parámetro de tipo genérico y el actualType
representa una de las restricciones dec
, o sic
representa un tipo de valor y el actualType
representaNullable<c>
(Nullable(Of c)
en Visual Basic).false
si ninguna de estas condiciones estrue
, o sic
esnull
.
Si Employee IsAssignableFrom T
luego T
hereda de Employee
.
El uso
typeof(T).IsAssignableFrom(typeof(Employee))
regresa true
solo cuando
T
y Employee
representan el mismo tipo; o,Employee
hereda de T
.Esto puede ser un uso intencionado en algún caso, pero para la pregunta original (y el uso más común), para determinar cuándo T
hereda o implementa algunos class
/ interface
, use:
typeof(Employee).IsAssignableFrom(typeof(T))
Lo que todos realmente quieren decir es:
typeof(BaseType).IsAssignableFrom(typeof(DerivedType)) // => true
porque literalmente puede asignar desde una instancia de a DerivedType
a una instancia de a BaseType
:
DerivedType childInstance = new DerivedType();
BaseType parentInstance = childInstance; // okay, assigning base from derived
childInstance = (DerivedType) parentInstance; // not okay, assigning derived from base
cuando
public class BaseType {}
public class DerivedType : BaseType {}
Y algunos ejemplos concretos si tiene problemas para entenderlo:
(a través de LinqPad, de ahí el 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;
}
baseclass-> baseclass
Cierto
niño1-> clase base
Falso
clase base-> niño1
Cierto
niño2-> clase base
Falso
clase base-> hijo2
Cierto
nobase-> clase base
Falso
clase base-> nobase
Falso
y
- FALLO: c1 = b1
- b1 = c1
- FALLO: c2 = b1
- b1 = c2
Aunque IsAssignableFrom es la mejor manera, como han dicho otros, si solo necesita verificar si una clase hereda de otra, typeof(T).BaseType == typeof(SomeClass)
también funciona.
SomeClass
que no se derive directamente de BaseClass
.
Las formas alternativas de saber si un objeto o
hereda una clase o implementa una interfaz es usar los operadores is
y as
.
Si solo desea saber si un objeto hereda una clase o implementa una interfaz, el is
operador devolverá un resultado booleano:
bool isCompatibleType = (o is BaseType || o is IInterface);
Si desea utilizar la clase heredada o la interfaz implementada después de su prueba, el as
operador realizará una conversión segura, devolviendo una referencia a la clase heredada o la interfaz implementada si es compatible o nula si no es 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 solo tiene el tipo T
, use la respuesta de @ nikeee.