Compruebe si 'T' hereda o implementa una clase / interfaz

92

¿Hay alguna forma de probar si T hereda / implementa una clase / interfaz?

private void MyGenericClass<T> ()
{
    if(T ... inherits or implements some class/interface
}
usuario1229895
fuente
4
esto parece funcionar ... si (typeof (TestClass) .IsAssignableFrom (typeof (T))), ¿alguien podría confirmar mis sospechas? ¡Gracias!
user1229895
¡Estoy absolutamente seguro de que esta respuesta se duplica muchas veces!
Felix K.
3
Felix K Incluso si esta respuesta se ha duplicado muchas veces, también ayuda a muchos muchachos muchas veces;) ... como yo hace cinco minutos :)
Samuel

Respuestas:

136

Existe un método llamado Type.IsAssignableFrom () .

Para comprobar si Thereda / 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).Ge‌​tTypeInfo())
nikeee
fuente
debe actualizar su respuesta con un ejemplo, por ejemplo, typeof (T) .IsAssignableFrom (typeof (IMyInterface))
Dr. Andrew Burnett-Thompson
Nikeee no hecho; la vieja respuesta sigue ahí. :) Tomé un par de segundos para averiguar qué estaba mal. De todos modos, +1, buena característica nuevamente del marco .net.
Samuel
De hecho, la forma en que mencionas es la forma en que lo tuve hace algún tiempo. Corregí este. Ver comentarios anteriores. T inherits Uen realidad se traduce en typeof(T).IsAssignableFrom(typeof(U)).
nikeee
3
Si bien esto casi funciona, existe un problema en el que si Testá restringido a algún otro tipo TOther, luego, cuando se ejecuta, en typeof(T)realidad se evaluará typeof(TOther)y no en el tipo Tque haya pasado realmente, y en ese caso, typeof(SomeInterface).IsAssignableFrom(typeof(T))fallará (suponiendo TOtherque no se implementa también SomeInterface), a pesar de que su tipo concreto se implementó SomeInterface.
Dave Cousineau
1
En .net, el núcleo IsAssignableFromde la TypeInfoclase solo acepta TypeInfo como su único argumento, por lo que la muestra debe ser la siguiente:typeof(Employee).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())
Para Ka el
16

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.

snajahi
fuente
12

La sintaxis correcta es

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

Documentación

Valor de retorno: true si cy el actual Typerepresentan el mismo tipo, o si el actual Typeestá en la jerarquía de herencia de c, o si el actual Typees un interfaceque cimplementa, o si ces un parámetro de tipo genérico y el actual Typerepresenta una de las restricciones de c, o si crepresenta un tipo de valor y el actual Typerepresenta Nullable<c>( Nullable(Of c)en Visual Basic). falsesi ninguna de estas condiciones es true, o si ces null.

fuente

Explicación

Si Employee IsAssignableFrom Tluego Thereda de Employee.

El uso

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

regresa true solo cuando

  1. Ty Employeerepresentan el mismo tipo; o,
  2. Employeehereda 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 Thereda o implementa algunos class/ interface, use:

typeof(Employee).IsAssignableFrom(typeof(T))
Luke
fuente
9

Lo que todos realmente quieren decir es:

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

porque literalmente puede asignar desde una instancia de a DerivedTypea 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 HorizontalRuny 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;
}

Resultados

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
drzaus
fuente
2

Creo que la sintaxis es: typeof(Employee).IsAssignableFrom(typeof(T));

Gredoso
fuente
Esta es la sintaxis deseada. +1
Lucas
0

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.

Jed
fuente
Eso funciona a menos SomeClassque no se derive directamente de BaseClass.
Suncat2000
0

Las formas alternativas de saber si un objeto ohereda una clase o implementa una interfaz es usar los operadores isy as.

Si solo desea saber si un objeto hereda una clase o implementa una interfaz, el isoperador 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 asoperador 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.

Suncat2000
fuente