Delen via


Procedure: Algemene typen onderzoeken en instantiëren met weerspiegeling

Informatie over algemene typen wordt op dezelfde manier verkregen als informatie over andere typen: door een Type object te onderzoeken dat het algemene type vertegenwoordigt. Het principeverschil is dat een algemeen type een lijst Type met objecten heeft die de algemene typeparameters vertegenwoordigen. De eerste procedure in deze sectie onderzoekt algemene typen.

U kunt een object maken dat een Type samengesteld type vertegenwoordigt door bindingstypeargumenten te gebruiken voor de typeparameters van een algemene typedefinitie. In de tweede procedure ziet u dit.

Een algemeen type en de bijbehorende typeparameters onderzoeken

  1. Haal een exemplaar op dat Type het algemene type vertegenwoordigt. In de volgende code wordt het type verkregen met behulp van de C# typeof -operator (GetType in Visual Basic, typeid in Visual C++). Zie het Type klasonderwerp voor andere manieren om een Type object op te halen. Houd er rekening mee dat het type in de rest van deze procedure is opgenomen in een methodeparameter met de naam t.

    Type^ d1 = Dictionary::typeid;
    
    Type d1 = typeof(Dictionary<,>);
    
    Dim d1 As Type = GetType(Dictionary(Of ,))
    
  2. Gebruik de IsGenericType eigenschap om te bepalen of het type algemeen is en gebruik de IsGenericTypeDefinition eigenschap om te bepalen of het type een algemene typedefinitie is.

    Console::WriteLine("   Is this a generic type? {0}",
        t->IsGenericType);
    Console::WriteLine("   Is this a generic type definition? {0}",
        t->IsGenericTypeDefinition);
    
    Console.WriteLine("   Is this a generic type? {0}",
        t.IsGenericType);
    Console.WriteLine("   Is this a generic type definition? {0}",
        t.IsGenericTypeDefinition);
    
    Console.WriteLine("   Is this a generic type? " _
        & t.IsGenericType)
    Console.WriteLine("   Is this a generic type definition? " _
        & t.IsGenericTypeDefinition)
    
  3. Haal een matrix op die de algemene typeargumenten bevat met behulp van de GetGenericArguments methode.

    array<Type^>^ typeParameters = t->GetGenericArguments();
    
    Type[] typeParameters = t.GetGenericArguments();
    
    Dim typeParameters() As Type = t.GetGenericArguments()
    
  4. Bepaal voor elk typeargument of het een typeparameter is (bijvoorbeeld in een algemene typedefinitie) of een type dat is opgegeven voor een typeparameter (bijvoorbeeld in een samengesteld typetype), met behulp van de IsGenericParameter eigenschap.

    Console::WriteLine("   List {0} type arguments:",
        typeParameters->Length);
    for each( Type^ tParam in typeParameters )
    {
        if (tParam->IsGenericParameter)
        {
            DisplayGenericParameter(tParam);
        }
        else
        {
            Console::WriteLine("      Type argument: {0}",
                tParam);
        }
    }
    
    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);
        }
    }
    
    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
    
  5. In het typesysteem wordt een algemene typeparameter vertegenwoordigd door een exemplaar van Type, net zoals gewone typen. De volgende code geeft de naam en parameterpositie weer van een Type object dat een algemene typeparameter vertegenwoordigt. De parameterpositie is hier triviale informatie; het is interessanter wanneer u een typeparameter onderzoekt die is gebruikt als een typeargument van een ander algemeen type.

    static void DisplayGenericParameter(Type^ tp)
    {
        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);
    
    Private Shared Sub DisplayGenericParameter(ByVal tp As Type)
        Console.WriteLine("      Type parameter: {0} position {1}", _
            tp.Name, tp.GenericParameterPosition)
    
  6. Bepaal de basistypebeperking en de interfacebeperkingen van een algemene typeparameter met behulp van de GetGenericParameterConstraints methode om alle beperkingen in één matrix te verkrijgen. Beperkingen zijn niet gegarandeerd in een bepaalde volgorde.

    Type^ classConstraint = nullptr;
    
    for each(Type^ iConstraint in tp->GetGenericParameterConstraints())
    {
        if (iConstraint->IsInterface)
        {
            Console::WriteLine("         Interface constraint: {0}",
                iConstraint);
        }
    }
    
    if (classConstraint != nullptr)
    {
        Console::WriteLine("         Base type constraint: {0}",
            tp->BaseType);
    }
    else
        Console::WriteLine("         Base type constraint: None");
    
    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");
    }
    
    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
    
  7. Gebruik de GenericParameterAttributes eigenschap om de speciale beperkingen voor een typeparameter te detecteren, zoals vereisen dat deze een verwijzingstype is. De eigenschap bevat ook waarden die afwijking vertegenwoordigen, die u kunt maskeren, zoals wordt weergegeven in de volgende code.

    GenericParameterAttributes sConstraints =
        tp->GenericParameterAttributes &
        GenericParameterAttributes::SpecialConstraintMask;
    
    GenericParameterAttributes sConstraints =
        tp.GenericParameterAttributes &
        GenericParameterAttributes.SpecialConstraintMask;
    
    Dim sConstraints As GenericParameterAttributes = _
        tp.GenericParameterAttributes And _
        GenericParameterAttributes.SpecialConstraintMask
    
  8. De speciale beperkingskenmerken zijn vlaggen en dezelfde vlag (GenericParameterAttributes.None) die geen speciale beperkingen vertegenwoordigt, vertegenwoordigt ook geen covariantie of contravariantie. Als u dus wilt testen op een van deze voorwaarden, moet u het juiste masker gebruiken. Gebruik in dit geval GenericParameterAttributes.SpecialConstraintMask om de speciale beperkingsvlagmen te isoleren.

    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.");
        }
    }
    
    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.");
        }
    }
    
    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
    

Een exemplaar van een algemeen type maken

Een algemeen type lijkt op een sjabloon. U kunt er geen exemplaren van maken, tenzij u echte typen opgeeft voor de algemene typeparameters. Als u dit tijdens runtime wilt doen, is de methode vereist MakeGenericType met behulp van weerspiegeling.

  1. Haal een Type object op dat het algemene type vertegenwoordigt. Met de volgende code wordt het algemene type Dictionary<TKey,TValue> op twee verschillende manieren opgehaald: met behulp van de overbelasting van de Type.GetType(String) methode met een tekenreeks die het type beschrijft en door de GetGenericTypeDefinition methode aan te roepen voor het samengestelde type Dictionary\<String, Example> (Dictionary(Of String, Example) in Visual Basic). Voor de MakeGenericType methode is een algemene typedefinitie vereist.

    // Use the typeid keyword to create the generic type
    // definition directly.
    Type^ d1 = Dictionary::typeid;
    
    // 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 = gcnew 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();
    
    // 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();
    
    ' 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()
    
  2. Maak een matrix van typeargumenten om te vervangen door de typeparameters. De matrix moet het juiste aantal Type objecten bevatten, in dezelfde volgorde als in de lijst met typeparameters. In dit geval is de sleutel (eerste parameter van het type) van het type Stringen de waarden in de woordenlijst zijn exemplaren van een klasse met de naam Example.

    array<Type^>^ typeArgs = {String::typeid, Example::typeid};
    
    Type[] typeArgs = {typeof(string), typeof(Example)};
    
    Dim typeArgs() As Type = _
        {GetType(String), GetType(Example)}
    
  3. Roep de MakeGenericType methode aan om de typeargumenten te binden aan de typeparameters en het type samen te stellen.

    Type^ constructed = d1->MakeGenericType(typeArgs);
    
    Type constructed = d1.MakeGenericType(typeArgs);
    
    Dim constructed As Type = _
        d1.MakeGenericType(typeArgs)
    
  4. Gebruik de overbelasting van de CreateInstance(Type) methode om een object van het samengestelde type te maken. In de volgende code worden twee exemplaren van de Example klasse opgeslagen in het resulterende Dictionary<String, Example> object.

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

Opmerking

In het volgende codevoorbeeld wordt een DisplayGenericType methode gedefinieerd om de algemene typedefinities en samengestelde typen te onderzoeken die in de code worden gebruikt en hun informatie weer te geven. De DisplayGenericType methode laat zien hoe u de IsGenericType, IsGenericParameteren GenericParameterPosition eigenschappen en de GetGenericArguments methode gebruikt.

In het voorbeeld wordt ook een DisplayGenericParameter methode gedefinieerd om een algemene typeparameter te onderzoeken en de beperkingen ervan weer te geven.

In het codevoorbeeld wordt een set testtypen gedefinieerd, waaronder een algemeen type dat beperkingen voor typeparameters illustreert en laat zien hoe u informatie over deze typen kunt weergeven.

In het voorbeeld wordt een type van de Dictionary<TKey,TValue> klasse samengesteld door een matrix van typeargumenten te maken en de methode aan te MakeGenericType roepen. Het programma vergelijkt het Type object dat is samengesteld met MakeGenericType een Type object dat is verkregen met behulp van typeof (GetType in Visual Basic) en laat zien dat ze hetzelfde zijn. Op dezelfde manier gebruikt het programma de GetGenericTypeDefinition methode om de algemene typedefinitie van het samengestelde type te verkrijgen en vergelijkt het met het Type object dat de Dictionary<TKey,TValue> klasse vertegenwoordigt.

using namespace System;
using namespace System::Reflection;
using namespace System::Collections::Generic;
using namespace System::Security::Permissions;

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

// Define an example base class.
public ref 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.

generic<class T>
    where T : TestBase, ITestArgument, gcnew()
public ref class Test {};

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

public ref 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.
        array<Type^>^ typeParameters = t->GetGenericArguments();

        Console::WriteLine("   List {0} type arguments:",
            typeParameters->Length);
        for each( 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.
    static void DisplayGenericParameter(Type^ tp)
    {
        Console::WriteLine("      Type parameter: {0} position {1}",
            tp->Name, tp->GenericParameterPosition);

        Type^ classConstraint = nullptr;

        for each(Type^ iConstraint in tp->GetGenericParameterConstraints())
        {
            if (iConstraint->IsInterface)
            {
                Console::WriteLine("         Interface constraint: {0}",
                    iConstraint);
            }
        }

        if (classConstraint != nullptr)
        {
            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.");
            }
        }
    }

public:
    [PermissionSetAttribute(SecurityAction::Demand, Name="FullTrust")]
    static void Main()
    {
        // Two ways to get a Type object that represents the generic
        // type definition of the Dictionary class.
        //
        // Use the typeid keyword to create the generic type
        // definition directly.
        Type^ d1 = Dictionary::typeid;

        // 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 = gcnew 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.
        array<Type^>^ typeArgs = {String::typeid, Example::typeid};

        // 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(Test::typeid);
    }
};

int main()
{
    Example::Main();
}
using System;
using System.Reflection;
using System.Collections.Generic;

// 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.");
            }
        }
    }

    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<>));
    }
}
Imports System.Reflection
Imports System.Collections.Generic

' 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

    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

Zie ook