Eu tenho uma classe genérica no meu projeto com classes derivadas.
public class GenericClass<T> : GenericInterface<T>
{
}
public class Test : GenericClass<SomeType>
{
}
Existe alguma maneira de descobrir se um Type
objeto é derivado GenericClass
?
t.IsSubclassOf(typeof(GenericClass<>))
não funciona.
c#
generics
reflection
Bernhardrusch
fonte
fonte
(Republicado devido a uma reescrita massiva)
A resposta de código do JaredPar é fantástica, mas tenho uma dica que tornaria desnecessária se seus tipos genéricos não fossem baseados em parâmetros de tipo de valor. Fiquei indiferente ao motivo pelo qual o operador "is" não funcionaria, por isso também documentei os resultados da minha experimentação para referência futura. Aumente esta resposta para aumentar ainda mais sua clareza.
DICA:
Se você garantir que sua implementação GenericClass herda de uma classe base não genérica abstrata, como GenericClassBase, você pode fazer a mesma pergunta sem nenhum problema como este:
IsSubclassOf ()
Meus testes indicam que IsSubclassOf () não funciona em tipos genéricos sem parâmetros, como
considerando que funcionará com
Portanto, o código a seguir funcionará para qualquer derivação de GenericClass <>, supondo que você esteja disposto a testar com base em SomeType:
A única vez em que posso imaginar que você deseja testar com GenericClass <> está em um cenário de estrutura de plug-in.
Pensamentos sobre o operador "is"
No tempo de design, o C # não permite o uso de genéricos sem parâmetros porque eles não são essencialmente um tipo completo de CLR nesse ponto. Portanto, você deve declarar variáveis genéricas com parâmetros, e é por isso que o operador "is" é tão poderoso para trabalhar com objetos. Aliás, o operador "is" também não pode avaliar tipos genéricos sem parâmetros.
O operador "is" testará toda a cadeia de herança, incluindo interfaces.
Portanto, dada uma instância de qualquer objeto, o seguinte método fará o truque:
Isso é meio redundante, mas imaginei que iria adiante e visualizaria para todos.
Dado
As seguintes linhas de código retornariam true:
Por outro lado, se você quiser algo específico para GenericClass, poderia torná-lo mais específico, suponho, assim:
Então você testaria assim:
fonte
Type
objeto.typeof
operador. De acordo com a documentação: "O operador typeof é usado para obter o objeto System.Type para um tipo".Eu trabalhei com algumas dessas amostras e descobri que elas estavam ausentes em alguns casos. Esta versão funciona com todos os tipos de genéricos: tipos, interfaces e definições de tipos.
Aqui estão os testes de unidade também:
fonte
!parent.IsGenericType || parent.GetGenericTypeDefinition() == parent;
Portanto, você substitui essa variável pela expansão da instrução if:if (parent.IsGenericType && shouldUseGenericType)
e obtém oif (parent.IsGenericType && (!parent.IsGenericType || parent.GetGenericTypeDefinition() == parent))
que é reduzido aif (parent.IsGenericType && parent.GetGenericTypeDefinition() == parent)) parent = parent.GetGenericTypeDefinition();
int j = 0;
if (j is an int && j == 0)
{ j=0; }
Estou obtendo minha referência igual e valor igual misturado? Eu pensei que havia apenas uma instância de cada tipo na memória, então duas variáveis que apontam para o mesmo tipo estão de fato apontando para o mesmo local na memória.Parece-me que essa implementação funciona em mais casos (classe genérica e interface com ou sem parâmetros iniciados, independentemente do número de filhos e parâmetros):
Aqui estão os meus
70casos de teste:Classes e interfaces para teste:
fonte
O código do JaredPar funciona, mas apenas para um nível de herança. Para níveis ilimitados de herança, use o seguinte código
fonte
while
código do JaredPar cobre níveis ilimitados.Aqui está um pequeno método que eu criei para verificar se um objeto é derivado de um tipo específico. Funciona muito bem para mim!
fonte
Pode ser um exagero, mas eu uso métodos de extensão como os seguintes. Eles verificam interfaces e subclasses. Também pode retornar o tipo que possui a definição genérica especificada.
Por exemplo, no exemplo da pergunta, ele pode testar contra interface genérica e classe genérica. O tipo retornado pode ser usado com
GetGenericArguments
para determinar que o tipo de argumento genérico é "SomeType".fonte
Com base na excelente resposta acima de fir3rpho3nixx e David Schmitt, modifiquei o código e adicionei o teste ShouldInheritOrImplementTypedGenericInterface (último).
fonte
Tudo isso pode ser feito facilmente com o linq. Isso encontrará todos os tipos que são uma subclasse da classe base genérica GenericBaseType.
fonte
Solução simples: basta criar e adicionar uma segunda interface não genérica à classe genérica:
Em seguida, basta verificar que, em qualquer forma que gosto de usar
is
,as
,IsAssignableFrom
, etc.Obviamente, só é possível se você tiver a capacidade de editar a classe genérica (que o OP parece ter), mas é um pouco mais elegante e legível do que usar um método de extensão criptográfica.
fonte
IGenericClass
não garante issoGenericClass
ouGenericInterface
é realmente estendido ou implementado. Isso significa que seu compilador também não permitirá que você acesse nenhum membro da classe genérica.Adicionado à resposta do @ jaredpar, eis o que eu uso para verificar as interfaces:
Ex:
fonte
JaredPar,
Isso não funcionou para mim se eu passar typeof (type <>) como toCheck. Aqui está o que eu mudei.
fonte
typeof(type<>)
comotoCheck
. Além disso, você realmente precisa da verificação nula, como na solução do JaredPar. Além disso, não sei o que mais você está conseguindo substituindocur == generic
na solução dele porcur.IsGenericType && generic.GetGenericTypeDefinition() == cur.GetGenericTypeDefinition()
não restringir seu método para funcionar apenas para tipos genéricos. Em outras palavras, qualquer coisa como isto falhar com uma exceção:IsSubclassOfRawGeneric(typeof(MyClass), typeof(MyClass<>))
@EnocNRoll - A resposta de Ananda Gopal é interessante, mas caso uma instância não seja instanciada anteriormente ou você queira verificar com uma definição de tipo genérica, sugiro este método:
e use-o como:
Existem quatro casos condicionais em que ambos
t
(a serem testados) ed
são tipos genéricos e dois casos são abrangidos pelost==d
quais (1) não ét
nemd
é uma definição genérica ou (2) ambos são definições genéricas . Nos demais casos, um deles é uma definição genérica; somente quandod
já é uma definição genérica, temos a chance de dizer que at
é uma,d
mas não vice-versa.Ele deve funcionar com classes ou interfaces arbitrárias que você deseja testar e retorna como se você testasse uma instância desse tipo com o
is
operador.fonte
fonte
Você pode tentar esta extensão
fonte
atrasado para o jogo sobre isso ... eu também tenho mais uma permutação da resposta de JarodPar.
aqui está Type.IsSubClassOf (Type), cortesia do refletor:
a partir disso, vemos que não está fazendo nada demais e é semelhante à abordagem iterativa de JaredPar. Por enquanto, tudo bem. aqui está minha versão (isenção de responsabilidade: não foi completamente testado, então deixe-me saber se você encontrar problemas)
basicamente, este é apenas um método de extensão para System.Type - fiz isso para limitar intencionalmente o tipo "thisType" a tipos concretos, pois meu uso imediato é a consulta LINQ "where" predicada em objetos Type. Tenho certeza de que todos vocês, pessoas inteligentes por aí, podem transformá-lo em um método estático eficiente e para todos os fins, se precisar :) o código faz algumas coisas que o código da resposta não
o resto é basicamente o mesmo que o código de JaredPar
fonte