Verifique se 'T' herda ou implementa uma classe / interface

92

Existe uma maneira de testar se T herda / implementa uma classe / interface?

private void MyGenericClass<T> ()
{
    if(T ... inherits or implements some class/interface
}
user1229895
fonte
4
isso parece funcionar ... if (typeof (TestClass) .IsAssignableFrom (typeof (T))), alguém poderia confirmar minhas suspeitas? obrigado!
user1229895
Tenho certeza absoluta de que essa resposta é duplicada muitas vezes!
Felix K.
3
Felix K Mesmo que esta resposta tenha sido duplicada muitas vezes, ela também ajuda muitos caras muitas vezes;) ... como eu há cinco minutos :)
Samuel

Respostas:

136

Existe um método chamado Type.IsAssignableFrom () .

Para verificar se Therda / 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).Ge‌​tTypeInfo())
nikeee
fonte
você deve atualizar sua resposta com um exemplo, por exemplo, typeof (T) .IsAssignableFrom (typeof (IMyInterface))
Dr. Andrew Burnett-Thompson
Não feito nikeee; a velha resposta ainda está lá. :) Demorei alguns segundos para descobrir o que estava errado. De qualquer forma, +1, bom recurso novamente do framework .net.
Samuel
Na verdade, o jeito que você mencionou é o mesmo que eu fazia há algum tempo. Eu corrigi este. Veja os comentários anteriores. T inherits Urealmente se traduz em typeof(T).IsAssignableFrom(typeof(U)).
nikeee
2
Embora isso quase funcione, há um problema em que se Tfor restrito a algum outro tipo TOther, então quando executado, typeof(T)irá realmente avaliar typeof(TOther)e não qualquer tipo que Tvocê realmente passou e, nesse caso, typeof(SomeInterface).IsAssignableFrom(typeof(T))irá falhar (assumindo TOtherque também não implementa SomeInterface), mesmo que seu tipo de concreto tenha implementado SomeInterface.
Dave Cousineau
1
No núcleo .net IsAssignableFromda TypeInfoclasse só aceita TypeInfo como seu único argumento, então o exemplo deve ser o seguinte:typeof(Employee).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())
Para Ka
16

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.

snajahi
fonte
12

A sintaxe correta é

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

Documentação

Valor de retorno: true se ce o atual Typerepresentam o mesmo tipo, ou se o atual Typeestá na hierarquia de herança de c, ou se o atual Typeé um interfaceque cimplementa, ou se cé um parâmetro de tipo genérico e o atual Typerepresenta uma das restrições de c, ou if crepresenta um tipo de valor e o atual Typerepresenta Nullable<c>( Nullable(Of c)no Visual Basic). falsese nenhuma dessas condições for true, ou se cfor null.

fonte

Explicação

Se Employee IsAssignableFrom Tentão Therda de Employee.

O uso

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

true retorna quando

  1. Te Employeerepresentam o mesmo tipo; ou,
  2. Employeeherda de T.

Este pode ser o uso pretendido em alguns casos, mas para a pergunta original (e o uso mais comum), para determinar quando Therda ou implementa algum class/ interface, use:

typeof(Employee).IsAssignableFrom(typeof(T))
Lucas
fonte
9

O que todos realmente querem dizer é:

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

porque você pode literalmente atribuir de uma instância de a DerivedTypea 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 HorizontalRune 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

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

Eu acredito que a sintaxe é: typeof(Employee).IsAssignableFrom(typeof(T));

Chalky
fonte
Esta é a sintaxe pretendida. +1
Luke
0

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á.

Jed
fonte
Isso funciona, a menos que SomeClassnão seja diretamente derivado de BaseClass.
Suncat2000,
0

Maneiras alternativas de saber se um objeto oherda uma classe ou implementa uma interface é usar os operadores ise as.

Se você quiser saber apenas se um objeto herda uma classe ou implementa uma interface, o isoperador 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 asoperador 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.

Suncat2000
fonte