Guide pratique pour examiner et instancier des types génériques avec la réflexion
Les informations sur les types génériques s’obtiennent de la même façon que les informations sur les autres types : en examinant un objet Type qui représente le type générique. La principale différence est qu’un type générique a une liste d’objets Type représentant ses paramètres de type générique. La première procédure de cette section examine les types génériques.
Vous pouvez créer un objet Type qui représente un type construit en liant des arguments de type aux paramètres de type d’une définition de type générique. Ceci est illustrée par la deuxième procédure.
Pour examiner un type générique et ses paramètres de type
Obtenez une instance de Type qui représente le type générique. Dans le code suivant, le type est obtenu à l’aide de l’opérateur C#
typeof
(GetType
en Visual Basic,typeid
en Visual C++). Pour découvrir d’autres méthodes d’obtention d’un objet Type, consultez la rubrique de la classe Type. Notez que dans le reste de cette procédure, le type est contenu dans un paramètre de méthode nommét
.Type^ d1 = Dictionary::typeid;
Type d1 = typeof(Dictionary<,>);
Dim d1 As Type = GetType(Dictionary(Of ,))
Utilisez la propriété IsGenericType pour déterminer si le type est générique, et utilisez la propriété IsGenericTypeDefinition pour déterminer si le type est une définition de type générique.
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)
Obtenez un tableau qui contient les arguments de type générique, à l’aide de la méthode GetGenericArguments.
array<Type^>^ typeParameters = t->GetGenericArguments();
Type[] typeParameters = t.GetGenericArguments();
Dim typeParameters() As Type = t.GetGenericArguments()
Pour chaque argument de type, déterminez s’il s’agit d’un paramètre de type (par exemple, dans une définition de type générique) ou d’un type qui a été spécifié pour un paramètre de type (par exemple, dans un type construit), à l’aide de la propriété IsGenericParameter.
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
Dans le système de type, un paramètre de type générique est représenté par une instance de Type, tout comme les types ordinaires. Le code suivant affiche le nom et la position du paramètre d’un objet Type qui représente un paramètre de type générique. La position di paramètre est ici sans importance. Elle est plus utile quand vous examinez un paramètre de type qui a été utilisé comme argument de type d’un autre type générique.
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)
Déterminez la contrainte de type de base et les contraintes d’interface d’un paramètre de type générique en utilisant la méthode GetGenericParameterConstraints pour obtenir toutes les contraintes dans un seul tableau. L’ordre des contraintes n’est pas garanti.
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
Utilisez la propriété GenericParameterAttributes pour découvrir les contraintes spéciales d’un paramètre de type, telles que l’obligation d’être un type référence. La propriété inclut également des valeurs qui représentent la variance, que vous pouvez masquer comme indiqué dans le code suivant.
GenericParameterAttributes sConstraints = tp->GenericParameterAttributes & GenericParameterAttributes::SpecialConstraintMask;
GenericParameterAttributes sConstraints = tp.GenericParameterAttributes & GenericParameterAttributes.SpecialConstraintMask;
Dim sConstraints As GenericParameterAttributes = _ tp.GenericParameterAttributes And _ GenericParameterAttributes.SpecialConstraintMask
Les attributs de contrainte spéciales sont des indicateurs, et l’indicateur (GenericParameterAttributes.None) qui ne représente aucune contrainte spéciale représente également aucune covariance ou contravariance. Ainsi, pour tester l’une de ces conditions, vous devez utiliser le masque approprié. Dans ce cas, utilisez GenericParameterAttributes.SpecialConstraintMask pour isoler les indicateurs de contraintes spéciales.
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
Construire une instance d’un type générique
Un type générique est comme un modèle. Vous ne pouvez pas créer des instances de ce type, sauf si vous spécifiez des types réels pour ses paramètres de type générique. Effectuer cela au moment de l’exécution à l’aide de la réflexion nécessite la méthode MakeGenericType.
Obtenez un objet Type qui représente le type générique. Le code suivant obtient le type générique Dictionary<TKey,TValue> de deux manières différentes : en utilisant la surcharge de méthode Type.GetType(String) avec une chaîne qui décrit le type, et en appelant la méthode GetGenericTypeDefinition sur le type construit
Dictionary\<String, Example>
(Dictionary(Of String, Example)
en Visual Basic). La méthode MakeGenericType nécessite une définition de type générique.// 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()
Créez un tableau d’arguments de type pour remplacer les paramètres de type. Le tableau doit contenir le nombre correct d’objets Type, dans l’ordre où ils apparaissent dans la liste de paramètres de type. Dans ce cas, la clé (premier paramètre de type) est de type String, et les valeurs dans le dictionnaire sont des instances d’une classe nommée
Example
.array<Type^>^ typeArgs = {String::typeid, Example::typeid};
Type[] typeArgs = {typeof(string), typeof(Example)};
Dim typeArgs() As Type = _ {GetType(String), GetType(Example)}
Appelez la méthode MakeGenericType pour lier les arguments de type aux paramètres de type et construire le type.
Type^ constructed = d1->MakeGenericType(typeArgs);
Type constructed = d1.MakeGenericType(typeArgs);
Dim constructed As Type = _ d1.MakeGenericType(typeArgs)
Utilisez la surcharge de méthode CreateInstance(Type) pour créer un objet du type construit. Le code suivant stocke deux instances de la classe
Example
dans l’objetDictionary<String, Example>
obtenu.Object^ o = Activator::CreateInstance(constructed);
object o = Activator.CreateInstance(constructed);
Dim o As Object = Activator.CreateInstance(constructed)
Exemple
L’exemple de code suivant définit une méthode DisplayGenericType
pour examiner les définitions de type générique et les types construits utilisés dans le code, et pour afficher leurs informations. La méthode DisplayGenericType
montre comment utiliser les propriétés IsGenericType, IsGenericParameter et GenericParameterPosition, et la méthode GetGenericArguments.
L’exemple définit également une méthode DisplayGenericParameter
pour examiner un paramètre de type générique et afficher ses contraintes.
L’exemple de code définit un ensemble de types de test, notamment un type générique qui illustre des contraintes de paramètre de type, et montre comment afficher des informations sur ces types.
L’exemple construit un type à partir de la classe Dictionary<TKey,TValue> en créant un tableau d’arguments de type et en appelant la méthode MakeGenericType. Le programme compare l’objet Type construit à l’aide de MakeGenericType avec un objet Type obtenu à l’aide de typeof
(GetType
en Visual Basic), et démontre qu’ils sont identiques. De même, le programme utilise la méthode GetGenericTypeDefinition pour obtenir la définition de type générique du type construit, et la compare à l’objet Type représentant la classe Dictionary<TKey,TValue>.
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