Partilhar via


Como: Examinar e instanciar tipos genéricos com reflexão

Informações sobre tipos genéricos são obtidas da mesma forma sistema autônomo sistema autônomo informações sobre outros tipos: examinando um Type objeto que representa o tipo genérico. A diferença de princípio é que um tipo genérico tem uma lista de Type objetos que representam seus parâmetros de tipo genérico. O primeiro procedimento nesta seção examina os tipos genéricos.

Você pode criar um Type objeto que representa um tipo construído pelos argumentos de tipo de ligação aos parâmetros de tipo de uma definição de tipo genérico. O segundo procedimento demonstra isso.

Para examinar um tipo genérico e seus parâmetros de tipo

  1. Obter uma instância de Type que representa o tipo genérico. O código a seguir, o tipo é obtido usando o translation from VPE for Csharp typeof () operadorGetType no Visual Basic typeid no Visual C++). Consulte o Type tópico da classe para outras maneiras de obter um Type objeto. Observe que o restante deste procedimento, o tipo está contido em um parâmetro do método chamado t.

    Dim d1 As Type = GetType(Dictionary(Of ,))
    
    Type d1 = typeof(Dictionary<,>);
    
  2. Use o IsGenericType propriedade para determinar se o tipo é genérico e usar o IsGenericTypeDefinition propriedade para determinar se o tipo é uma definição de tipo genérico.

    Console.WriteLine("   Is this a generic type? " _ 
        & t.IsGenericType)
    Console.WriteLine("   Is this a generic type definition? " _ 
        & t.IsGenericTypeDefinition)
    
    Console.WriteLine("   Is this a generic type? {0}",
        t.IsGenericType);
    Console.WriteLine("   Is this a generic type definition? {0}",
        t.IsGenericTypeDefinition);
    
  3. Obtenha uma matriz que contém os argumentos de tipo genérico, usando o GetGenericArguments método.

    Dim typeParameters() As Type = t.GetGenericArguments()
    
    Type[] typeParameters = t.GetGenericArguments();
    
  4. Para cada argumento de tipo, determinar se ele é um parâmetro de tipo (por exemplo, em uma definição de tipo genérico) ou um tipo que foi especificado para um parâmetro de tipo (por exemplo, em um tipo construído), usando o IsGenericParameter propriedade.

    Console.WriteLine("   List {0} type arguments:", _
        typeParameters.Length)
    For Each tParam As Type In typeParameters
        If tParam.IsGenericParameter Then
            DisplayGenericParameter(tParam)
        Else
            Console.WriteLine("      Type argument: {0}", _
                tParam)
        End If
    Next
    
    Console.WriteLine("   List {0} type arguments:", 
        typeParameters.Length);
    foreach( Type tParam in typeParameters )
    {
        if (tParam.IsGenericParameter)
        {
            DisplayGenericParameter(tParam);
        }
        else
        {
            Console.WriteLine("      Type argument: {0}",
                tParam);
        }
    }
    
  5. No sistema de tipo, um parâmetro de tipo genérico é representado por uma instância de Type, assim sistema autônomo tipos comuns são. O código a seguir exibe a posição do nome e o parâmetro de um Type objeto que representa um parâmetro de tipo genérico. A posição de parâmetro é triviais informações aqui; é mais interessantes durante o exame de um parâmetro de tipo que foi usado sistema autônomo argumento de tipo de outro tipo genérico.

    Private Shared Sub DisplayGenericParameter(ByVal tp As Type)
        Console.WriteLine("      Type parameter: {0} position {1}", _
            tp.Name, tp.GenericParameterPosition)
    
    private static void DisplayGenericParameter(Type tp)
    {
        Console.WriteLine("      Type parameter: {0} position {1}", 
            tp.Name, tp.GenericParameterPosition);
    
  6. Determine a restrição do tipo de base e as restrições de interface de um parâmetro de tipo genérico usando o GetGenericParameterConstraints método para obter todas as restrições em um único array. As restrições não são garantidas como em uma ordem específica.

    Dim classConstraint As Type = Nothing
    
    For Each iConstraint As Type In tp.GetGenericParameterConstraints()
        If iConstraint.IsInterface Then
            Console.WriteLine("         Interface constraint: {0}", _
                iConstraint)
        End If
    Next
    
    If classConstraint IsNot Nothing Then
        Console.WriteLine("         Base type constraint: {0}", _
            tp.BaseType)
    Else
        Console.WriteLine("         Base type constraint: None")
    End If
    
    Type classConstraint = null;
    
    foreach(Type iConstraint in tp.GetGenericParameterConstraints())
    {
        if (iConstraint.IsInterface)
        {
            Console.WriteLine("         Interface constraint: {0}",
                iConstraint);
        }
    }
    
    if (classConstraint != null)
    {
        Console.WriteLine("         Base type constraint: {0}", 
            tp.BaseType);
    }
    else
        Console.WriteLine("         Base type constraint: None"); 
    
  7. Use o GenericParameterAttributes propriedade para descobrir sistema autônomo restrições especiais em um parâmetro de tipo, sistema autônomo solicitar que ele seja um tipo de referência. A propriedade inclui também sistema autônomo valores que representam variação, que você pode mascarar logoff sistema autônomo mostra o código a seguir.

    Dim sConstraints As GenericParameterAttributes = _
        tp.GenericParameterAttributes And _
        GenericParameterAttributes.SpecialConstraintMask
    
    GenericParameterAttributes sConstraints = 
        tp.GenericParameterAttributes & 
        GenericParameterAttributes.SpecialConstraintMask;
    
  8. Os atributos da restrição especiais são sinalizadores e o mesmo sinalizar (GenericParameterAttributes.None) que não represente nenhuma especiais restrições também representa sem covariância ou contravariance. Portanto, para testar qualquer uma das seguintes condições, você deve usar a máscara apropriada.Nesse caso, use GenericParameterAttributes.SpecialConstraintMask para isolar os sinalizadores especiais restrição.

    If sConstraints = GenericParameterAttributes.None Then
        Console.WriteLine("         No special constraints.")
    Else
        If GenericParameterAttributes.None <> (sConstraints And _
            GenericParameterAttributes.DefaultConstructorConstraint) Then
            Console.WriteLine("         Must have a parameterless constructor.")
        End If
        If GenericParameterAttributes.None <> (sConstraints And _
            GenericParameterAttributes.ReferenceTypeConstraint) Then
            Console.WriteLine("         Must be a reference type.")
        End If
        If GenericParameterAttributes.None <> (sConstraints And _
            GenericParameterAttributes.NotNullableValueTypeConstraint) Then
            Console.WriteLine("         Must be a non-nullable value type.")
        End If
    End If
    
    if (sConstraints == GenericParameterAttributes.None)
    {
        Console.WriteLine("         No special constraints.");
    }
    else
    {
        if (GenericParameterAttributes.None != (sConstraints &
            GenericParameterAttributes.DefaultConstructorConstraint))
        {
            Console.WriteLine("         Must have a parameterless constructor.");
        }
        if (GenericParameterAttributes.None != (sConstraints &
            GenericParameterAttributes.ReferenceTypeConstraint))
        {
            Console.WriteLine("         Must be a reference type.");
        }
        if (GenericParameterAttributes.None != (sConstraints &
            GenericParameterAttributes.NotNullableValueTypeConstraint))
        {
            Console.WriteLine("         Must be a non-nullable value type.");
        }
    }
    

Construir uma instância de um tipo genérico

É um tipo genérico como um modelo.Não é possível criar instâncias dele, a menos que você especifique tipos reais para seus parâmetros de tipo genérico.Para fazer isso em time de execução, usando a reflexão, requer o MakeGenericType método.

Construir uma instância de um tipo genérico

  1. Obtenha um Type objeto que representa o tipo genérico. O código a seguir obtém o tipo genérico Dictionary<TKey, TValue> de duas maneiras diferentes: usando o Type.GetType(String) sobrecarga de método com uma seqüência de caracteres que descreve o tipo e chamando o GetGenericTypeDefinition método no tipo construído Dictionary<String, Example> (Dictionary(Of String, Example) no Visual Basic). The MakeGenericType método requer uma definição de tipo genérico.

    ' Use the GetType operator to create the generic type 
    ' definition directly. To specify the generic type definition,
    ' omit the type arguments but retain the comma that separates
    ' them.
    Dim d1 As Type = GetType(Dictionary(Of ,))
    
    ' You can also obtain the generic type definition from a
    ' constructed class. In this case, the constructed class
    ' is a dictionary of Example objects, with String keys.
    Dim d2 As New Dictionary(Of String, Example)
    ' Get a Type object that represents the constructed type,
    ' and from that get the generic type definition. The 
    ' variables d1 and d4 contain the same type.
    Dim d3 As Type = d2.GetType()
    Dim d4 As Type = d3.GetGenericTypeDefinition()
    
    // Use the typeof operator to create the generic type 
    // definition directly. To specify the generic type definition,
    // omit the type arguments but retain the comma that separates
    // them.
    Type d1 = typeof(Dictionary<,>);
    
    // You can also obtain the generic type definition from a
    // constructed class. In this case, the constructed class
    // is a dictionary of Example objects, with String keys.
    Dictionary<string, Example> d2 = new Dictionary<string, Example>();
    // Get a Type object that represents the constructed type,
    // and from that get the generic type definition. The 
    // variables d1 and d4 contain the same type.
    Type d3 = d2.GetType();
    Type d4 = d3.GetGenericTypeDefinition();
    
  2. Construa uma matriz de argumentos de tipo para substituir os parâmetros de tipo.A matriz deve conter o número correto de Type objetos, na mesma ordem em que aparecem na lista de parâmetros de tipo. Nesse caso, a chave (primeiro tipo de parâmetro) é do tipo String, e os valores no dicionário são instâncias de uma classe chamada Example.

    Dim typeArgs() As Type = _
        { GetType(String), GetType(Example) }
    
    Type[] typeArgs = {typeof(string), typeof(Example)};
    
  3. Chamar o MakeGenericType método para BIND os argumentos de tipo para os parâmetros de tipo e construir o tipo.

    Dim constructed As Type = _
        d1.MakeGenericType(typeArgs)
    
    Type constructed = d1.MakeGenericType(typeArgs);
    
  4. Use o CreateInstance(Type) método de sobrecarga para criar um objeto do tipo construído. O código a seguir armazena duas instâncias do Example classe resultante Dictionary<String, Example> objeto.

    Dim o As Object = Activator.CreateInstance(constructed)
    
    object o = Activator.CreateInstance(constructed);
    

Exemplo

O exemplo de código a seguir define um DisplayGenericType método para examinar as definições de tipo genérico e os tipos construídos usados no código e exibir suas informações. The DisplayGenericType método mostra como usar o IsGenericType, IsGenericParameter, e GenericParameterPosition propriedades e o GetGenericArguments método.

O exemplo também define um DisplayGenericParameter método para examinar um genérico parâmetro de tipo e exibir suas restrições.

O exemplo de código define um conjunto de tipos de teste, incluindo um tipo genérico que ilustra as restrições de parâmetro de tipo e mostra como exibir informações sobre esses tipos.

O exemplo constrói um tipo a partir de Dictionary<TKey, TValue> classe de criação de uma matriz de argumentos de tipo e chamando o MakeGenericType método. O programa compara o Type objeto construído usando MakeGenericType com um Type objeto obtido usando typeof (GetType no Visual Basic), demonstrando que eles são os mesmos. Da mesma forma, o programa usa o GetGenericTypeDefinition método para obter a definição de tipo genérico do tipo construído e compara-o para o Type objeto que representa o Dictionary<TKey, TValue> classe.

Imports System
Imports System.Reflection
Imports System.Collections.Generic
Imports System.Security.Permissions

' Define an example interface.
Public Interface ITestArgument
End Interface

' Define an example base class.
Public Class TestBase
End Class

' Define a generic class with one parameter. The parameter
' has three constraints: It must inherit TestBase, it must
' implement ITestArgument, and it must have a parameterless
' constructor.
Public Class Test(Of T As {TestBase, ITestArgument, New})
End Class

' Define a class that meets the constraints on the type
' parameter of class Test.
Public Class TestArgument
    Inherits TestBase
    Implements ITestArgument
    Public Sub New()
    End Sub
End Class

Public Class Example
    ' The following method displays information about a generic
    ' type.
    Private Shared Sub DisplayGenericType(ByVal t As Type)
        Console.WriteLine(vbCrLf & t.ToString())
        Console.WriteLine("   Is this a generic type? " _ 
            & t.IsGenericType)
        Console.WriteLine("   Is this a generic type definition? " _ 
            & t.IsGenericTypeDefinition)

        ' Get the generic type parameters or type arguments.
        Dim typeParameters() As Type = t.GetGenericArguments()

        Console.WriteLine("   List {0} type arguments:", _
            typeParameters.Length)
        For Each tParam As Type In typeParameters
            If tParam.IsGenericParameter Then
                DisplayGenericParameter(tParam)
            Else
                Console.WriteLine("      Type argument: {0}", _
                    tParam)
            End If
        Next
    End Sub

    ' The following method displays information about a generic
    ' type parameter. Generic type parameters are represented by
    ' instances of System.Type, just like ordinary types.
    Private Shared Sub DisplayGenericParameter(ByVal tp As Type)
        Console.WriteLine("      Type parameter: {0} position {1}", _
            tp.Name, tp.GenericParameterPosition)

        Dim classConstraint As Type = Nothing

        For Each iConstraint As Type In tp.GetGenericParameterConstraints()
            If iConstraint.IsInterface Then
                Console.WriteLine("         Interface constraint: {0}", _
                    iConstraint)
            End If
        Next

        If classConstraint IsNot Nothing Then
            Console.WriteLine("         Base type constraint: {0}", _
                tp.BaseType)
        Else
            Console.WriteLine("         Base type constraint: None")
        End If

        Dim sConstraints As GenericParameterAttributes = _
            tp.GenericParameterAttributes And _
            GenericParameterAttributes.SpecialConstraintMask
        If sConstraints = GenericParameterAttributes.None Then
            Console.WriteLine("         No special constraints.")
        Else
            If GenericParameterAttributes.None <> (sConstraints And _
                GenericParameterAttributes.DefaultConstructorConstraint) Then
                Console.WriteLine("         Must have a parameterless constructor.")
            End If
            If GenericParameterAttributes.None <> (sConstraints And _
                GenericParameterAttributes.ReferenceTypeConstraint) Then
                Console.WriteLine("         Must be a reference type.")
            End If
            If GenericParameterAttributes.None <> (sConstraints And _
                GenericParameterAttributes.NotNullableValueTypeConstraint) Then
                Console.WriteLine("         Must be a non-nullable value type.")
            End If
        End If
    End Sub

    <PermissionSetAttribute(SecurityAction.Demand, Name:="FullTrust")> _
    Public Shared Sub Main()
        ' Two ways to get a Type object that represents the generic
        ' type definition of the Dictionary class. 
        '
        ' Use the GetType operator to create the generic type 
        ' definition directly. To specify the generic type definition,
        ' omit the type arguments but retain the comma that separates
        ' them.
        Dim d1 As Type = GetType(Dictionary(Of ,))

        ' You can also obtain the generic type definition from a
        ' constructed class. In this case, the constructed class
        ' is a dictionary of Example objects, with String keys.
        Dim d2 As New Dictionary(Of String, Example)
        ' Get a Type object that represents the constructed type,
        ' and from that get the generic type definition. The 
        ' variables d1 and d4 contain the same type.
        Dim d3 As Type = d2.GetType()
        Dim d4 As Type = d3.GetGenericTypeDefinition()

        ' Display information for the generic type definition, and
        ' for the constructed type Dictionary(Of String, Example).
        DisplayGenericType(d1)
        DisplayGenericType(d2.GetType())

        ' Construct an array of type arguments to substitute for 
        ' the type parameters of the generic Dictionary class.
        ' The array must contain the correct number of types, in 
        ' the same order that they appear in the type parameter 
        ' list of Dictionary. The key (first type parameter)
        ' is of type string, and the type to be contained in the
        ' dictionary is Example.
        Dim typeArgs() As Type = _
            { GetType(String), GetType(Example) }

        ' Construct the type Dictionary(Of String, Example).
        Dim constructed As Type = _
            d1.MakeGenericType(typeArgs)

        DisplayGenericType(constructed)

        Dim o As Object = Activator.CreateInstance(constructed)

        Console.WriteLine(vbCrLf & _
            "Compare types obtained by different methods:")
        Console.WriteLine("   Are the constructed types equal? " _
            & (d2.GetType() Is constructed))
        Console.WriteLine("   Are the generic definitions equal? " _ 
            & (d1 Is constructed.GetGenericTypeDefinition()))

        ' Demonstrate the DisplayGenericType and 
        ' DisplayGenericParameter methods with the Test class 
        ' defined above. This shows base, interface, and special
        ' constraints.
        DisplayGenericType(GetType(Test(Of )))
    End Sub
End Class
using System;
using System.Reflection;
using System.Collections.Generic;
using System.Security.Permissions;

// Define an example interface.
public interface ITestArgument {}

// Define an example base class.
public class TestBase {}

// Define a generic class with one parameter. The parameter
// has three constraints: It must inherit TestBase, it must
// implement ITestArgument, and it must have a parameterless
// constructor.
public class Test<T> where T : TestBase, ITestArgument, new() {}

// Define a class that meets the constraints on the type
// parameter of class Test.
public class TestArgument : TestBase, ITestArgument
{
    public TestArgument() {}
}

public class Example
{
    // The following method displays information about a generic
    // type.
    private static void DisplayGenericType(Type t)
    {
        Console.WriteLine("\r\n {0}", t);
        Console.WriteLine("   Is this a generic type? {0}",
            t.IsGenericType);
        Console.WriteLine("   Is this a generic type definition? {0}",
            t.IsGenericTypeDefinition);

        // Get the generic type parameters or type arguments.
        Type[] typeParameters = t.GetGenericArguments();

        Console.WriteLine("   List {0} type arguments:", 
            typeParameters.Length);
        foreach( Type tParam in typeParameters )
        {
            if (tParam.IsGenericParameter)
            {
                DisplayGenericParameter(tParam);
            }
            else
            {
                Console.WriteLine("      Type argument: {0}",
                    tParam);
            }
        }
    }

    // The following method displays information about a generic
    // type parameter. Generic type parameters are represented by
    // instances of System.Type, just like ordinary types.
    private static void DisplayGenericParameter(Type tp)
    {
        Console.WriteLine("      Type parameter: {0} position {1}", 
            tp.Name, tp.GenericParameterPosition);

        Type classConstraint = null;

        foreach(Type iConstraint in tp.GetGenericParameterConstraints())
        {
            if (iConstraint.IsInterface)
            {
                Console.WriteLine("         Interface constraint: {0}",
                    iConstraint);
            }
        }

        if (classConstraint != null)
        {
            Console.WriteLine("         Base type constraint: {0}", 
                tp.BaseType);
        }
        else
            Console.WriteLine("         Base type constraint: None"); 

        GenericParameterAttributes sConstraints = 
            tp.GenericParameterAttributes & 
            GenericParameterAttributes.SpecialConstraintMask;

        if (sConstraints == GenericParameterAttributes.None)
        {
            Console.WriteLine("         No special constraints.");
        }
        else
        {
            if (GenericParameterAttributes.None != (sConstraints &
                GenericParameterAttributes.DefaultConstructorConstraint))
            {
                Console.WriteLine("         Must have a parameterless constructor.");
            }
            if (GenericParameterAttributes.None != (sConstraints &
                GenericParameterAttributes.ReferenceTypeConstraint))
            {
                Console.WriteLine("         Must be a reference type.");
            }
            if (GenericParameterAttributes.None != (sConstraints &
                GenericParameterAttributes.NotNullableValueTypeConstraint))
            {
                Console.WriteLine("         Must be a non-nullable value type.");
            }
        }
    }

    [PermissionSetAttribute(SecurityAction.Demand, Name="FullTrust")]
    public static void Main()
    {
        // Two ways to get a Type object that represents the generic
        // type definition of the Dictionary class. 
        //
        // Use the typeof operator to create the generic type 
        // definition directly. To specify the generic type definition,
        // omit the type arguments but retain the comma that separates
        // them.
        Type d1 = typeof(Dictionary<,>);

        // You can also obtain the generic type definition from a
        // constructed class. In this case, the constructed class
        // is a dictionary of Example objects, with String keys.
        Dictionary<string, Example> d2 = new Dictionary<string, Example>();
        // Get a Type object that represents the constructed type,
        // and from that get the generic type definition. The 
        // variables d1 and d4 contain the same type.
        Type d3 = d2.GetType();
        Type d4 = d3.GetGenericTypeDefinition();

        // Display information for the generic type definition, and
        // for the constructed type Dictionary<String, Example>.
        DisplayGenericType(d1);
        DisplayGenericType(d2.GetType());

        // Construct an array of type arguments to substitute for 
        // the type parameters of the generic Dictionary class.
        // The array must contain the correct number of types, in 
        // the same order that they appear in the type parameter 
        // list of Dictionary. The key (first type parameter)
        // is of type string, and the type to be contained in the
        // dictionary is Example.
        Type[] typeArgs = {typeof(string), typeof(Example)};

        // Construct the type Dictionary<String, Example>.
        Type constructed = d1.MakeGenericType(typeArgs);

        DisplayGenericType(constructed);

        object o = Activator.CreateInstance(constructed);

        Console.WriteLine("\r\nCompare types obtained by different methods:");
        Console.WriteLine("   Are the constructed types equal? {0}",
            (d2.GetType()==constructed));
        Console.WriteLine("   Are the generic definitions equal? {0}",
            (d1==constructed.GetGenericTypeDefinition()));

        // Demonstrate the DisplayGenericType and 
        // DisplayGenericParameter methods with the Test class 
        // defined above. This shows base, interface, and special
        // constraints.
        DisplayGenericType(typeof(Test<>));
    }
}

Compilando o código

  • O código contém o translation from VPE for Csharp using () instruçõesImports no Visual Basic) necessário para compilação.

  • Nenhuma referência de assembly adicionais é necessária.

  • compilar o código na linha de comando usando csc.exe, vbc.exe ou cl.exe.Para compilar o código no Visual Studio, coloque-o em um modelo de projeto de aplicativo de console.

Consulte também

Conceitos

Exibindo informações de tipo

Visão geral das classes genéricas no .NET Framework

Referência

Type

MethodInfo

Outros recursos

Reflexão e tipos genérico