Partilhar 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érica) 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éricas e definições de método genérico são representados por instâncias da Type classe.

    Nota

    Muitas propriedades e métodos têm comportamento diferente quando um Type objeto representa um parâmetro de Type 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 de representa um tipo genérico, então ela inclui uma matriz de tipos que representam os parâmetros de tipo (para definições de tipo genéricas) ou os argumentos de Type tipo (para tipos construídos). O mesmo é verdadeiro para 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 de representa um parâmetro de Type tipo ou um tipo real.

Para obter um código de exemplo demonstrando 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.

Trata-se de um tipo ou método genérico?

Quando você usa 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 retorna true se o tipo for genérico. Da mesma forma, quando você examinar um método desconhecido, representado por uma instância da MethodInfo classe, use a IsGenericMethod propriedade para determinar se o método é genérico.

Trata-se de uma definição genérica de tipo ou método?

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

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

O tipo ou método é aberto ou fechado?

Um tipo ou método genérico é fechado se os tipos instanciáveis tiverem sido substituídos para todos os seus parâmetros de tipo, incluindo todos os parâmetros de tipo de todos os tipos anexos. Você só pode criar uma instância de um tipo genérico se ela estiver fechada. A Type.ContainsGenericParameters propriedade retorna 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 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 para um método genérico fechado.

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

Se você tiver um tipo ou método genérico aberto que não seja um tipo genérico ou definição de método, não poderá criar instâncias dele e não poderá fornecer os parâmetros de tipo que estão faltando. Você deve ter um tipo genérico ou definição de método. Use o GetGenericTypeDefinition método para obter a definição de tipo genérica 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>, você pode 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 Parâmetro de tipo ou argumento de tipo.

Examinar argumentos de tipo e parâmetros de tipo

Use o Type.GetGenericArguments método para obter uma matriz de objetos que representam os parâmetros de Type 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 de saber que um Type objeto representa um parâmetro type, há muitas perguntas adicionais que a reflexão pode responder. Você pode determinar a origem do parâmetro type, sua posição e suas restrições.

Parâmetro de tipo ou argumento de tipo

Para determinar se um elemento específico da matriz é um parâmetro de tipo ou um argumento de tipo, use a IsGenericParameter propriedade. A IsGenericParameter propriedade é true se o elemento for um parâmetro type.

Um tipo genérico pode ser aberto sem ser uma definição de tipo genérica, caso em que 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 primeiro parâmetro de tipo de D pelo segundo parâmetro de 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
generic<typename T, typename U> ref class B {};
generic<typename V, typename W> ref class D : B<int, V> {};

Se você obtiver um Type objeto que represente D<V, W> e use 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érica.

Fonte de um parâmetro genérico

Um parâmetro de tipo genérico pode vir do tipo que você está examinando, de um tipo anexado 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 type vem de um método genérico. Se o valor da propriedade não for uma referência nula, a fonte 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 type pertence a um método genérico, a DeclaringType propriedade retorna 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 declarante. 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ê examina V , pode usar as DeclaringMethod propriedades e DeclaringType para descobrir de onde vem. Em seguida, você pode usar a GenericParameterPosition propriedade para determinar sua posição na lista de parâmetros de tipo onde ela foi definida. Neste exemplo, V está na posição 0 (zero) na lista de parâmetros de tipo onde foi definido.

Tipo de base e restrições de interface

Use o GetGenericParameterConstraints método para obter a restrição de tipo base e as restrições de interface de um parâmetro type. 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âmetros genéricos

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

Covariância e contravariância

Para determinar se um parâmetro type é 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 type é invariante. Para obter mais informações, consulte Covariância e contravariância.

Condicionalismos especiais

Para determinar as restrições especiais de um parâmetro type, aplique a GenericParameterAttributes.SpecialConstraintMask máscara ao GenericParameterAttributes valor retornado pela GenericParameterAttributes propriedade. Se o resultado for GenericParameterAttributes.None, não há restrições especiais. Um parâmetro type 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.

Invariantes

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