Compartilhar via


Reflexão e tipos genéricos

Do ponto de vista da reflexão, a diferença entre um tipo genérico e um tipo comum é que um tipo genérico tem associado a ele um conjunto de parâmetros de tipo (se for uma definição de tipo genérico) ou argumentos de tipo (se for um tipo construído). Um método genérico difere de um método comum da mesma maneira.

Há duas chaves para entender como a reflexão lida com tipos e métodos genéricos:

  • Os parâmetros de tipo de definições de tipo genérico e definições de método genérico são representados por instâncias da Type classe.

    Observação

    Muitas propriedades e métodos têm Type um comportamento diferente quando um Type objeto representa um parâmetro de tipo genérico. Essas diferenças estão documentadas nos artigos de propriedade e método. Por exemplo, veja IsAutoClass e DeclaringType. Além disso, alguns membros são válidos somente quando um Type objeto representa um parâmetro de tipo genérico. Por exemplo, veja GetGenericTypeDefinition.

  • Se uma instância representar Type um tipo genérico, ela incluirá uma matriz de tipos que representam os parâmetros de tipo (para definições de tipo genérico) ou os argumentos de tipo (para tipos construídos). O mesmo se aplica a uma instância da MethodInfo classe que representa um método genérico.

A reflexão fornece métodos de Type e MethodInfo que permitem acessar a matriz de parâmetros de tipo e determinar se uma instância representa um parâmetro de Type tipo ou um tipo real.

Por exemplo, código que demonstra os métodos discutidos aqui, consulte Como examinar e instanciar tipos genéricos com reflexão.

A discussão a seguir pressupõe familiaridade com a terminologia de genéricos, como a diferença entre parâmetros de tipo e argumentos e tipos construídos abertos ou fechados. Para obter mais informações, consulte Genéricos.

Esse é um tipo ou método genérico?

Ao usar a reflexão para examinar um tipo desconhecido, representado por uma instância de Type, use a IsGenericType propriedade para determinar se o tipo desconhecido é genérico. Ele retornará true se o tipo for genérico. Da mesma forma, ao examinar um método desconhecido, representado por uma instância da classe, use a MethodInfoIsGenericMethod propriedade para determinar se o método é genérico.

É um tipo genérico ou uma definição de método?

Use a IsGenericTypeDefinition propriedade para determinar se um Type objeto representa uma definição de tipo genérico e use o IsGenericMethodDefinition método para determinar se um representa uma MethodInfo definição de método genérico.

Definições genéricas de tipo e método são os modelos dos quais tipos instanciáveis são criados. Tipos genéricos nas bibliotecas .NET, como Dictionary<TKey,TValue>, por exemplo, são definições de tipo genérico.

O tipo ou método está aberto ou fechado?

Um tipo ou método genérico será fechado se tipos instanciáveis tiverem sido substituídos por todos os parâmetros de tipo, incluindo todos os parâmetros de tipo de todos os tipos delimitantes. Você só poderá criar uma instância de um tipo genérico se ela estiver fechada. A Type.ContainsGenericParameters propriedade retornará true se um tipo estiver aberto. Para métodos, o MethodBase.ContainsGenericParameters método executa a mesma função.

Gerar tipos genéricos fechados

Depois de ter um tipo genérico ou uma definição de método, use o MakeGenericType método para criar um tipo genérico fechado ou o MakeGenericMethod método para criar um MethodInfo método genérico fechado.

Obter o tipo genérico ou a definição de método

Se você tiver um tipo ou método genérico aberto que não seja um tipo genérico ou uma definição de método, não poderá criar instâncias dele e não poderá fornecer os parâmetros de tipo ausentes. Você deve ter um tipo genérico ou uma definição de método. Use o GetGenericTypeDefinition método para obter a definição de tipo genérico ou o GetGenericMethodDefinition método para obter a definição de método genérico.

Por exemplo, se você tiver um Type objeto representando Dictionary<int, string> e quiser criar o tipo Dictionary<string, MyClass>, poderá usar o GetGenericTypeDefinition método para obter uma Type representação Dictionary<TKey, TValue> e, em seguida, usar o MakeGenericType método para produzir uma Type representação Dictionary<int, MyClass>.

Para obter um exemplo de um tipo genérico aberto que não é um tipo genérico, consulte o parâmetro Type ou o argumento type.

Examinar argumentos de tipo e parâmetros de tipo

Use o Type.GetGenericArguments método para obter uma matriz de Type objetos que representam os parâmetros de tipo ou argumentos de tipo de um tipo genérico e use o MethodInfo.GetGenericArguments método para fazer o mesmo para um método genérico.

Depois que você souber que um Type objeto representa um parâmetro de tipo, há muitas perguntas adicionais que a reflexão pode responder. Você pode determinar a origem do parâmetro de tipo, sua posição e suas restrições.

Tipo de parâmetro ou argumento de tipo

Para determinar se um determinado elemento da matriz é um parâmetro de tipo ou um argumento de tipo, use a IsGenericParameter propriedade. A IsGenericParameter propriedade será true se o elemento for um parâmetro de tipo.

Um tipo genérico pode ser aberto sem ser uma definição de tipo genérico, nesse caso, ele tem uma mistura de argumentos de tipo e parâmetros de tipo. Por exemplo, no código a seguir, a classe D deriva de um tipo criado substituindo o parâmetro de primeiro tipo do D parâmetro de segundo tipo de B.

class B<T, U> {}
class D<V, W> : B<int, V> {}
Class B(Of T, U)
End Class
Class D(Of V, W)
    Inherits B(Of Integer, V)
End Class

Se você obter um Type objeto representando D<V, W> e usar a BaseType propriedade para obter seu tipo base, o resultado type B<int, V> será aberto, mas não será uma definição de tipo genérico.

Origem de um parâmetro genérico

Um parâmetro de tipo genérico pode vir do tipo que você está examinando, de um tipo delimitante ou de um método genérico. Você pode determinar a origem do parâmetro de tipo genérico da seguinte maneira:

  • Primeiro, use a DeclaringMethod propriedade para determinar se o parâmetro de tipo vem de um método genérico. Se o valor da propriedade não for uma referência nula, a origem será um método genérico.
  • Se a origem não for um método genérico, use a DeclaringType propriedade para determinar o tipo genérico ao qual o parâmetro de tipo genérico pertence.

Se o parâmetro de tipo pertencer a um método genérico, a DeclaringType propriedade retornará o tipo que declarou o método genérico, que é irrelevante.

Posição de um parâmetro genérico

Em situações raras, é necessário determinar a posição de um parâmetro de tipo na lista de parâmetros de tipo de sua classe de declaração. Por exemplo, suponha que você tenha um Type objeto representando o B<int, V> tipo do exemplo anterior. O GetGenericArguments método fornece uma lista de argumentos de tipo e, quando você examinaV, pode usar as propriedades e DeclaringMethod as DeclaringType propriedades para descobrir de onde ela vem. Em seguida, você pode usar a GenericParameterPosition propriedade para determinar sua posição na lista de parâmetros de tipo em que ela foi definida. Neste exemplo, V está na posição 0 (zero) na lista de parâmetros de tipo em que foi definida.

Restrições de tipo base e interface

Use o GetGenericParameterConstraints método para obter a restrição de tipo base e as restrições de interface de um parâmetro de tipo. A ordem dos elementos da matriz não é significativa. Um elemento representa uma restrição de interface se for um tipo de interface.

Atributos de parâmetro genéricos

A GenericParameterAttributes propriedade obtém um GenericParameterAttributes valor que indica a variação (covariância ou contravariância) e as restrições especiais de um parâmetro de tipo.

Covariância e contravariância

Para determinar se um parâmetro de tipo é covariante ou contravariante, aplique a GenericParameterAttributes.VarianceMask máscara ao GenericParameterAttributes valor retornado pela GenericParameterAttributes propriedade. Se o resultado for GenericParameterAttributes.None, o parâmetro de tipo será invariável. Para obter mais informações, consulte Covariance e Contravariance.

Restrições especiais

Para determinar as restrições especiais de um parâmetro de tipo, aplique a GenericParameterAttributes.SpecialConstraintMask máscara ao GenericParameterAttributes valor retornado pela GenericParameterAttributes propriedade. Se o resultado for GenericParameterAttributes.None, não haverá restrições especiais. Um parâmetro de tipo pode ser restrito a ser um tipo de referência, ser um tipo de valor não anulável e ter um construtor sem parâmetros.

Invariáveis

Para obter uma tabela das condições invariáveis para termos comuns em reflexão para tipos genéricos, consulte Type.IsGenericType. Para termos adicionais relacionados a métodos genéricos, consulte MethodBase.IsGenericMethod.