Type.MakeGenericType(Type[]) Método

Definição

Substitui os elementos de uma matriz de tipos para os parâmetros de tipo da definição de tipo genérico atual e retorna um Type objeto que representa o tipo construído resultante.

public:
 abstract Type ^ MakeGenericType(... cli::array <Type ^> ^ typeArguments);
public:
 virtual Type ^ MakeGenericType(... cli::array <Type ^> ^ typeArguments);
public abstract Type MakeGenericType(params Type[] typeArguments);
[System.Diagnostics.CodeAnalysis.RequiresDynamicCode("The native code for this instantiation might not be available at runtime.")]
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")]
public virtual Type MakeGenericType(params Type[] typeArguments);
public virtual Type MakeGenericType(params Type[] typeArguments);
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")]
public virtual Type MakeGenericType(params Type[] typeArguments);
abstract member MakeGenericType : Type[] -> Type
[<System.Diagnostics.CodeAnalysis.RequiresDynamicCode("The native code for this instantiation might not be available at runtime.")>]
[<System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")>]
abstract member MakeGenericType : Type[] -> Type
override this.MakeGenericType : Type[] -> Type
abstract member MakeGenericType : Type[] -> Type
override this.MakeGenericType : Type[] -> Type
[<System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")>]
abstract member MakeGenericType : Type[] -> Type
override this.MakeGenericType : Type[] -> Type
Public MustOverride Function MakeGenericType (ParamArray typeArguments As Type()) As Type
Public Overridable Function MakeGenericType (ParamArray typeArguments As Type()) As Type

Parâmetros

typeArguments
Type[]

Uma matriz de tipos a ser substituída pelos parâmetros de tipo do tipo genérico atual.

Retornos

Um Type que representa o tipo construído formado substituindo os elementos dos parâmetros de typeArguments tipo do tipo genérico atual.

Atributos

Exceções

O tipo atual não representa uma definição de tipo genérico. Ou seja, IsGenericTypeDefinition retorna false.

typeArguments é null.

- ou -

Qualquer elemento é typeArgumentsnull.

O número de elementos não typeArguments é o mesmo que o número de parâmetros de tipo na definição de tipo genérico atual.

- ou -

Qualquer elemento não typeArguments atende às restrições especificadas para o parâmetro de tipo correspondente do tipo genérico atual.

- ou -

typeArguments contém um elemento que é um tipo de ponteiro (IsPointer retorna true), um tipo por ref (IsByRef retorna true) ou Void.

Não há suporte para o método invocado na classe base. Classes derivadas devem fornecer uma implementação.

Exemplos

O exemplo a seguir usa o MakeGenericType método para criar um tipo construído a partir da definição de tipo genérico para o Dictionary<TKey,TValue> tipo. O tipo construído representa um Dictionary<TKey,TValue> dos objetos com chaves de Test cadeia de caracteres.

using System;
using System.Reflection;
using System.Collections.Generic;

public class Test
{
    public static void Main()
    {
        Console.WriteLine("\r\n--- Create a constructed type from the generic Dictionary type.");

        // Create a type object representing the generic Dictionary 
        // type, by omitting the type arguments (but keeping the 
        // comma that separates them, so the compiler can infer the
        // number of type parameters).      
        Type generic = typeof(Dictionary<,>);
        DisplayTypeInfo(generic);

        // Create an array of types to substitute for the type
        // parameters of Dictionary. The key is of type string, and
        // the type to be contained in the Dictionary is Test.
        Type[] typeArgs = { typeof(string), typeof(Test) };

        // Create a Type object representing the constructed generic
        // type.
        Type constructed = generic.MakeGenericType(typeArgs);
        DisplayTypeInfo(constructed);

        // Compare the type objects obtained above to type objects
        // obtained using typeof() and GetGenericTypeDefinition().
        Console.WriteLine("\r\n--- Compare types obtained by different methods:");

        Type t = typeof(Dictionary<String, Test>);
        Console.WriteLine("\tAre the constructed types equal? {0}", t == constructed);
        Console.WriteLine("\tAre the generic types equal? {0}", 
            t.GetGenericTypeDefinition() == generic);
    }

    private static void DisplayTypeInfo(Type t)
    {
        Console.WriteLine("\r\n{0}", t);

        Console.WriteLine("\tIs this a generic type definition? {0}", 
            t.IsGenericTypeDefinition);

        Console.WriteLine("\tIs it a generic type? {0}", 
            t.IsGenericType);

        Type[] typeArguments = t.GetGenericArguments();
        Console.WriteLine("\tList type arguments ({0}):", typeArguments.Length);
        foreach (Type tParam in typeArguments)
        {
            Console.WriteLine("\t\t{0}", tParam);
        }
    }
}

/* This example produces the following output:

--- Create a constructed type from the generic Dictionary type.

System.Collections.Generic.Dictionary`2[TKey,TValue]
        Is this a generic type definition? True
        Is it a generic type? True
        List type arguments (2):
                TKey
                TValue

System.Collections.Generic.Dictionary`2[System.String, Test]
        Is this a generic type definition? False
        Is it a generic type? True
        List type arguments (2):
                System.String
                Test

--- Compare types obtained by different methods:
        Are the constructed types equal? True
        Are the generic types equal? True
 */
open System
open System.Collections.Generic

type Test() = class end

let displayTypeInfo (t: Type) =
    printfn $"\r\n{t}"

    printfn $"\tIs this a generic type definition? {t.IsGenericTypeDefinition}" 

    printfn $"\tIs it a generic type? {t.IsGenericType}"

    let typeArguments = t.GetGenericArguments()
    printfn $"\tList type arguments ({typeArguments.Length}):"
    for tParam in typeArguments do
        printfn $"\t\t{tParam}"

printfn "\r\n--- Create a constructed type from the generic Dictionary type."

// Create a type object representing the generic Dictionary 
// type, by calling .GetGenericTypeDefinition().
let generic = typeof<Dictionary<_,_>>.GetGenericTypeDefinition()
displayTypeInfo generic

// Create an array of types to substitute for the type
// parameters of Dictionary. The key is of type string, and
// the type to be contained in the Dictionary is Test.
let typeArgs = [| typeof<string>; typeof<Test> |]

// Create a Type object representing the constructed generic type.
let constructed = generic.MakeGenericType typeArgs
displayTypeInfo constructed

(* This example produces the following output:

--- Create a constructed type from the generic Dictionary type.

System.Collections.Generic.Dictionary`2[TKey,TValue]
        Is this a generic type definition? True
        Is it a generic type? True
        List type arguments (2):
                TKey
                TValue

System.Collections.Generic.Dictionary`2[System.String, Test]
        Is this a generic type definition? False
        Is it a generic type? True
        List type arguments (2):
                System.String
                Test
 *)

Public Class Test
    Public Shared Sub Main2()
        Console.WriteLine(vbCrLf & "--- Create a constructed type from the generic Dictionary type.")

        ' Create a type object representing the generic Dictionary 
        ' type, by omitting the type arguments (but keeping the 
        ' comma that separates them, so the compiler can infer the
        ' number of type parameters).
        Dim generic As Type = GetType(Dictionary(Of ,))
        DisplayTypeInfo(generic)

        ' Create an array of types to substitute for the type
        ' parameters of Dictionary. The key is of type string, and
        ' the type to be contained in the Dictionary is Test.
        Dim typeArgs() As Type = {GetType(String), GetType(Test)}

        ' Create a Type object representing the constructed generic
        ' type.
        Dim constructed As Type = generic.MakeGenericType(typeArgs)
        DisplayTypeInfo(constructed)

        ' Compare the type objects obtained above to type objects
        ' obtained using GetType() and GetGenericTypeDefinition().
        Console.WriteLine(vbCrLf & "--- Compare types obtained by different methods:")

        Dim t As Type = GetType(Dictionary(Of String, Test))
        Console.WriteLine(vbTab & "Are the constructed types equal? " _
            & (t Is constructed))
        Console.WriteLine(vbTab & "Are the generic types equal? " _
            & (t.GetGenericTypeDefinition() Is generic))
    End Sub

    Private Shared Sub DisplayTypeInfo(ByVal t As Type)
        Console.WriteLine(vbCrLf & t.ToString())

        Console.WriteLine(vbTab & "Is this a generic type definition? " _ 
            & t.IsGenericTypeDefinition)

        Console.WriteLine(vbTab & "Is it a generic type? " _ 
            & t.IsGenericType)

        Dim typeArguments() As Type = t.GetGenericArguments()
        Console.WriteLine(vbTab & "List type arguments ({0}):", _
            typeArguments.Length)
        For Each tParam As Type In typeArguments       
            Console.WriteLine(vbTab & vbTab & tParam.ToString())
        Next
    End Sub
End Class

' This example produces the following output:
'
'--- Create a constructed type from the generic Dictionary type.
'
'System.Collections.Generic.Dictionary'2[TKey,TValue]
'        Is this a generic type definition? True
'        Is it a generic type? True
'        List type arguments (2):
'                TKey
'                TValue
'
'System.Collections.Generic.Dictionary`2[System.String,Test]
'        Is this a generic type definition? False
'        Is it a generic type? True
'        List type arguments (2):
'                System.String
'                Test
'
'--- Compare types obtained by different methods:
'        Are the constructed types equal? True
'        Are the generic types equal? True

Comentários

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

Os tipos construídos com MakeGenericType podem ser abertos, ou seja, alguns de seus argumentos de tipo podem ser parâmetros de tipo de métodos ou tipos genéricos abrangentes. Você pode usar esses tipos construídos abertos ao criar 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 um assembly dinâmico, é necessário construir seu tipo base. Para fazer isso, chame o método MakeGenericType em um objeto Type que representa a classe Base, usando argumentos de tipo genérico Int32 e o parâmetro de tipo V de Derived. Como os tipos e os parâmetros de tipo genérico são representados por Type objetos, uma matriz que contém ambos pode ser passada para o MakeGenericType método.

Note

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 ele não é uma definição de tipo genérico. Para criar um tipo construído fechado que possa ser instanciado, primeiro chame o GetGenericTypeDefinition método para obter um Type objeto que represente a definição de tipo genérico e, em seguida, chame MakeGenericType com os argumentos de tipo desejados.

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

Note

Uma matriz de tipos genéricos não é em si um tipo genérico. Não é possível 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 de C<T>[], chame GetElementType para obter a definição de tipo genérico C<T>; chame MakeGenericType na definição de tipo genérico para criar o tipo construído; e, por fim, chame o método MakeArrayType no tipo construído para criar o tipo de matriz. O mesmo vale para tipos de ponteiro e tipos ref (ByRef no Visual Basic).

Para obter uma lista das condições invariantes para termos usados na reflexão genérica, veja as observações 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 é verdade mesmo que os tipos aninhados não tenham seus próprios parâmetros de tipo, porque todos os três idiomas incluem os parâmetros de tipo dos tipos envolventes nas listas de parâmetros de tipo dos 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 aninhada Inner tem dois parâmetros de tipo, T e U, sendo que o primeiro deles é o parâmetro de tipo de sua classe que a contém. Da mesma forma, a lista de parâmetros de tipo da classe Innermost1 aninhada tem três parâmetros de tipo, TUe , com VT e U vindo de suas classes delimitantes. A classe Innermost2 aninhada tem dois parâmetros de tipo, T e U, que vêm de suas classes envolventes.

Se a lista de parâmetros do tipo delimitante tiver mais de um parâmetro de tipo, todos os parâmetros de tipo na 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 método MakeGenericType usando a matriz formada pela concatenação das matrizes de argumento de tipo de todos os tipos circundantes, começando pelo tipo genérico mais externo e terminando com a matriz de argumento de tipo do próprio tipo aninhado, se tiver parâmetros de tipo próprios. Para criar uma instância de Innermost1, chame o MakeGenericType método com uma matriz contendo três tipos, a ser atribuída a T, U e V. Para criar uma instância de Innermost2, chame o MakeGenericType método com uma matriz contendo dois tipos, a ser atribuída a T e U.

As linguagens propagam os parâmetros de tipo de tipos envolventes dessa forma, permitindo que você utilize os parâmetros de tipo de um tipo envolvente para definir campos de subtipos. 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 de tipos delimitadores, emitindo código em assemblies dinâmicos ou usando o Ilasm.exe (IL Assembler). Considere o seguinte código para o CIL assembler:

.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 de classe Innermost, porque esses parâmetros de tipo não estão no escopo. O código do assembler a seguir define classes aninhadas que se comportam da maneira que se 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 nos idiomas de alto nível e observar esse esquema de nomenclatura.

Aplica-se a

Confira também