Como: Examinar e instanciar tipos genéricos com reflexão
As informações sobre tipos genéricos são obtidas da mesma forma que as informações sobre outros tipos: examinando um Type objeto que representa o tipo genérico. A principal diferença é que um tipo genérico tem uma lista de objetos que representam seus parâmetros de Type tipo genéricos. O primeiro procedimento desta secção examina os tipos genéricos.
Você pode criar um Type objeto que representa um tipo construído vinculando argumentos de tipo aos parâmetros de tipo de uma definição de tipo genérica. O segundo procedimento demonstra-o.
Para examinar um tipo genérico e seus parâmetros de tipo
Obtenha uma instância que Type representa o tipo genérico. No código a seguir, o tipo é obtido usando o operador C#
typeof
(GetType
no Visual Basic,typeid
no Visual C++). Consulte o tópico da Type classe para obter outras maneiras de obter um Type objeto. Observe que, no restante deste procedimento, o tipo está contido em um parâmetro de método chamadot
.Type^ d1 = Dictionary::typeid;
Type d1 = typeof(Dictionary<,>);
Dim d1 As Type = GetType(Dictionary(Of ,))
Use a IsGenericType propriedade para determinar se o tipo é genérico e use a IsGenericTypeDefinition propriedade para determinar se o tipo é uma definição de tipo genérica.
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)
Obtenha uma matriz que contém os argumentos de tipo genéricos, usando o GetGenericArguments método.
array<Type^>^ typeParameters = t->GetGenericArguments();
Type[] typeParameters = t.GetGenericArguments();
Dim typeParameters() As Type = t.GetGenericArguments()
Para cada argumento type, determine se é um parâmetro type (por exemplo, em uma definição genérica de tipo) ou um tipo que foi especificado para um parâmetro type (por exemplo, em um tipo construído), usando a IsGenericParameter propriedade.
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
No sistema de tipos, um parâmetro de tipo genérico é representado por uma instância de Type, assim como os tipos comuns. O código a seguir exibe o nome e a posição do parâmetro de um Type objeto que representa um parâmetro de tipo genérico. A posição do parâmetro é uma informação trivial aqui; É de maior interesse quando você está examinando um parâmetro de tipo que foi usado como um argumento de tipo de outro tipo genérico.
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)
Determine a restrição de tipo 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 uma única matriz. Não é garantido que as restrições estejam em qualquer ordem específica.
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
Use a GenericParameterAttributes propriedade para descobrir as restrições especiais em um parâmetro type, como exigir que seja um tipo de referência. A propriedade também inclui valores que representam variância, que você pode mascarar como mostrado no código a seguir.
GenericParameterAttributes sConstraints = tp->GenericParameterAttributes & GenericParameterAttributes::SpecialConstraintMask;
GenericParameterAttributes sConstraints = tp.GenericParameterAttributes & GenericParameterAttributes.SpecialConstraintMask;
Dim sConstraints As GenericParameterAttributes = _ tp.GenericParameterAttributes And _ GenericParameterAttributes.SpecialConstraintMask
Os atributos de restrição especial são sinalizadores, e o mesmo sinalizador (GenericParameterAttributes.None) que não representa restrições especiais também não representa nenhuma covariância ou contravariância. Assim, para testar qualquer uma destas condições deve usar a máscara adequada. Nesse caso, use GenericParameterAttributes.SpecialConstraintMask para isolar os sinalizadores de restrição especial.
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
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 especifique tipos reais para seus parâmetros de tipo genéricos. Para fazer isso em tempo de execução, usando reflexão, requer o MakeGenericType método.
Obtenha um Type objeto que represente o tipo genérico. O código a seguir obtém o tipo Dictionary<TKey,TValue> genérico de duas maneiras diferentes: usando a sobrecarga de Type.GetType(String) método com uma cadeia de caracteres descrevendo o tipo e chamando o GetGenericTypeDefinition método no tipo
Dictionary\<String, Example>
construído (Dictionary(Of String, Example)
no Visual Basic). O MakeGenericType método requer uma definição de tipo genérica.// 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()
Construa uma matriz de argumentos de tipo para substituir os parâmetros de tipo. A matriz deve conter o número correto de objetos, na mesma ordem em que aparecem na lista de Type parâmetros de tipo. Nesse caso, a chave (primeiro parâmetro de tipo) é do tipo String, e os valores no dicionário são instâncias de uma classe chamada
Example
.array<Type^>^ typeArgs = {String::typeid, Example::typeid};
Type[] typeArgs = {typeof(string), typeof(Example)};
Dim typeArgs() As Type = _ {GetType(String), GetType(Example)}
Chame o MakeGenericType método para vincular os argumentos de tipo aos parâmetros de tipo e construa o tipo.
Type^ constructed = d1->MakeGenericType(typeArgs);
Type constructed = d1.MakeGenericType(typeArgs);
Dim constructed As Type = _ d1.MakeGenericType(typeArgs)
Use a CreateInstance(Type) sobrecarga de método para criar um objeto do tipo construído. O código a seguir armazena duas instâncias da
Example
classe no objeto resultanteDictionary<String, Example>
.Object^ o = Activator::CreateInstance(constructed);
object o = Activator.CreateInstance(constructed);
Dim o As Object = Activator.CreateInstance(constructed)
Exemplo
O exemplo de código a seguir define um DisplayGenericType
método para examinar as definições de tipo genéricas e os tipos construídos usados no código e exibir suas informações. O DisplayGenericType
método mostra como usar as IsGenericTypepropriedades , IsGenericParametere GenericParameterPosition e o GetGenericArguments método.
O exemplo também define um DisplayGenericParameter
método para examinar um parâmetro de tipo genérico e exibir suas restrições.
O exemplo de código define um conjunto de tipos de teste, incluindo um tipo genérico que ilustra restrições de parâmetro de tipo e mostra como exibir informações sobre esses tipos.
O exemplo constrói um tipo a Dictionary<TKey,TValue> partir da classe criando 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
em Visual Basic), demonstrando que eles são os mesmos. Da mesma forma, o programa usa o GetGenericTypeDefinition método para obter a definição genérica de tipo do tipo construído e compara-o com o Type objeto que representa a Dictionary<TKey,TValue> classe.
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