Método System.Type.MakeGenericType

Este artigo fornece observações complementares à documentação de referência para essa API.

O MakeGenericType método permite que você escreva código que atribui tipos específicos aos parâmetros de tipo de uma definição de tipo genérica, criando assim um Type objeto que representa um tipo construído específico. Você pode usar esse Type objeto para criar instâncias de tempo de execução do tipo construído.

Tipos construídos com MakeGenericType podem ser abertos, ou seja, alguns de seus argumentos de tipo podem ser parâmetros de tipo de inclusão de métodos genéricos ou tipos. Você pode usar esses tipos construídos abertos ao emitir assemblies dinâmicos. Por exemplo, considere as classes Base e Derived no código a seguir.

public class Base<T, U> { }
public class Derived<V> : Base<int, V> { }
type Base<'T, 'U>() = class end
type Derived<'V>() = inherit Base<int, 'V>()
Public Class Base(Of T, U)
End Class
Public Class Derived(Of V)
    Inherits Base(Of Integer, V)
End Class

Para gerar Derived em uma montagem dinâmica, é necessário construir seu tipo base. Para fazer isso, chame o MakeGenericType método em um Type objeto que representa a classe Base, usando os argumentos Int32 de tipo genérico e o parâmetro V de tipo de Derived. Como os tipos e os parâmetros de tipo genéricos são representados por Type objetos, uma matriz contendo ambos pode ser passada para o MakeGenericType método.

Observação

Um tipo construído como Base<int, V> é útil ao emitir código, mas você não pode chamar o MakeGenericType método nesse tipo porque não é uma definição de tipo genérica. Para criar um tipo construído fechado que pode ser instanciado, primeiro chame o GetGenericTypeDefinition método para obter um Type objeto que representa a definição de tipo genérico e, em seguida, chame MakeGenericType com os argumentos de tipo desejados.

O Type objeto retornado por MakeGenericType é o mesmo obtido Type chamando o GetType método do tipo construído resultante ou o GetType método de qualquer tipo construído que foi criado a partir da mesma definição de tipo genérico usando os mesmos argumentos de tipo.

Observação

Uma matriz de tipos genéricos não é em si um tipo genérico. Você não pode chamar MakeGenericType um tipo de matriz como C<T>[] (Dim ac() As C(Of T) no Visual Basic). Para construir um tipo genérico fechado a partir do , chame GetElementType para obter a definição C<T>de tipo genérico , chame MakeGenericType a definição de C<T>[]tipo genérico para criar o tipo construído e, finalmente, chame o MakeArrayType método no tipo construído para criar o tipo de matriz. O mesmo é verdadeiro para tipos de ponteiro e ref tipos (ByRef no Visual Basic).

Para obter uma lista das condições invariáveis para termos usados na reflexão genérica, consulte os comentários da propriedade IsGenericType.

Tipos aninhados

Se um tipo genérico for definido usando C#, C++ ou Visual Basic, seus tipos aninhados serão todos genéricos. Isso é verdadeiro mesmo se os tipos aninhados não tiverem parâmetros de tipo próprios, porque todos os três idiomas incluem os parâmetros de tipo de tipos incluídos nas listas de parâmetros de tipo de tipos aninhados. Considere as seguintes classes:

public class Outermost<T>
{
    public class Inner<U>
    {
        public class Innermost1<V> {}
        public class Innermost2 {}
    }
}
Public Class Outermost(Of T)
    Public Class Inner(Of U)
        Public Class Innermost1(Of V)
        End Class
        Public Class Innermost2
        End Class
    End Class
End Class

A lista de parâmetros de tipo da classe Inner aninhada tem dois parâmetros T de tipo e U, o primeiro dos quais é o parâmetro de tipo de sua classe de delimitação. Da mesma forma, a lista de parâmetros de tipo da classe Innermost1 aninhada tem três parâmetros de tipo, T, Ue V, com T e U provenientes de suas classes de delimitação. A classe Innermost2 aninhada tem dois parâmetros T de tipo e U, que vêm de suas classes de delimitação.

Se a lista de parâmetros do tipo de fechamento tiver mais de um parâmetro de tipo, todos os parâmetros de tipo em ordem serão incluídos na lista de parâmetros de tipo do tipo aninhado.

Para construir um tipo genérico a partir da definição de tipo genérico para um tipo aninhado, chame o MakeGenericType método com a matriz formada concatenando as matrizes de argumento de tipo de todos os tipos de delimitação, começando com o tipo genérico mais externo e terminando com a matriz de argumento de tipo do próprio tipo aninhado, se ele tiver parâmetros de tipo próprios. Para criar uma instância do Innermost1, chame o MakeGenericType método com uma matriz contendo três tipos, a serem atribuídos a T, U e V. Para criar uma instância do Innermost2, chame o MakeGenericType método com uma matriz contendo dois tipos, a serem atribuídos a T e U.

As linguagens propagam os parâmetros de tipo de tipos de delimitação dessa maneira para que você possa usar os parâmetros de tipo de um tipo de delimitação para definir campos de tipos aninhados. Caso contrário, os parâmetros de tipo não estariam no escopo dentro dos corpos dos tipos aninhados. É possível definir tipos aninhados sem propagar os parâmetros de tipo dos tipos de delimitação, emitindo código em montagens dinâmicas ou usando o Ilasm.exe (IL Assembler). Considere o seguinte código para o montador CIL:

.class public Outer<T> {
    .class nested public Inner<U> {
        .class nested public Innermost {
        }
    }
}

Neste exemplo, não é possível definir um campo de tipo T ou U em classe Innermost, porque esses parâmetros de tipo não estão no escopo. O código assembler a seguir define classes aninhadas que se comportam da maneira que se fossem definidas em C++, Visual Basic e C#:

.class public Outer<T> {
    .class nested public Inner<T, U> {
        .class nested public Innermost<T, U, V> {
        }
    }
}

Você pode usar o Ildasm.exe (IL Disassembler) para examinar classes aninhadas definidas nas linguagens de alto nível e observar esse esquema de nomenclatura.