How to: Examine and Instantiate Generic Types with Reflection
Microsoft Silverlight will reach end of support after October 2021. Learn more.
Information about generic types is obtained in the same way as information about other types: by examining a Type object that represents the generic type. The principal difference is that a generic type has a list of Type objects that represent its generic type parameters. The first procedure in this topic examines generic types.
You can create a Type object that represents a constructed type by binding type arguments to the type parameters of a generic type definition. The second procedure demonstrates this.
To examine a generic type and its type parameters
Get an instance of Type that represents the generic type. In the following code, the type is obtained by using the C# typeof operator (GetType in Visual Basic, typeid in Visual C++). See the Type class topic for other ways to get a Type object. Note that in the rest of this procedure, the type is contained in a method parameter named t.
Dim d1 As Type = GetType(Dictionary(Of ,))
Type d1 = typeof(Dictionary<,>);
Use the IsGenericType property to determine whether the type is generic, and use the IsGenericTypeDefinition property to determine whether the type is a generic type definition.
output.Text &= " Is this a generic type? " _ & t.IsGenericType & vbCrLf output.Text &= " Is this a generic type definition? " _ & t.IsGenericTypeDefinition & vbCrLf
output.Text += String.Format(" Is this a generic type? {0}\r\n", t.IsGenericType); output.Text += String.Format(" Is this a generic type definition? {0}\r\n", t.IsGenericTypeDefinition);
Get an array that contains the generic type arguments, using the GetGenericArguments method.
Dim typeParameters() As Type = t.GetGenericArguments()
Type[] typeParameters = t.GetGenericArguments();
For each type argument, determine whether it is a type parameter (for example, in a generic type definition) or a type that has been specified for a type parameter (for example, in a constructed type), using the IsGenericParameter property.
output.Text &= String.Format(" List {0} type arguments:" & vbCrLf, _ typeParameters.Length) For Each tParam As Type In typeParameters If tParam.IsGenericParameter Then DisplayGenericParameter(tParam) Else output.Text &= String.Format(" Type argument: {0}" & vbCrLf, _ tParam) End If Next
output.Text += String.Format(" List {0} type arguments:\r\n", typeParameters.Length); foreach( Type tParam in typeParameters ) { if (tParam.IsGenericParameter) { DisplayGenericParameter(tParam); } else { output.Text += String.Format(" Type argument: {0}\r\n", tParam); } }
In the type system, a generic type parameter is represented by an instance of Type, just as ordinary types are. The following code displays the name and parameter position of a Type object that represents a generic type parameter. The parameter position is trivial information here; it is of more interest when you are examining a type parameter that has been used as a type argument of another generic type.
Private Shared Sub DisplayGenericParameter(ByVal tp As Type) output.Text &= String.Format(" Type parameter: {0} position {1}" & vbCrLf, _ tp.Name, tp.GenericParameterPosition)
private static void DisplayGenericParameter(Type tp) { output.Text += String.Format(" Type parameter: {0} position {1}\r\n", tp.Name, tp.GenericParameterPosition);
Determine the base type constraint and the interface constraints of a generic type parameter by using the GetGenericParameterConstraints method to obtain all the constraints in a single array. Constraints are not guaranteed to be in any particular order.
Dim classConstraint As Type = Nothing For Each iConstraint As Type In tp.GetGenericParameterConstraints() If iConstraint.IsInterface Then output.Text &= String.Format(" Interface constraint: {0}" & vbCrLf, _ iConstraint) End If Next If classConstraint IsNot Nothing Then output.Text &= String.Format(" Base type constraint: {0}" & vbCrLf, _ tp.BaseType) Else output.Text &= " Base type constraint: None" & vbCrLf End If
Type classConstraint = null; foreach(Type iConstraint in tp.GetGenericParameterConstraints()) { if (iConstraint.IsInterface) { output.Text += String.Format(" Interface constraint: {0}\r\n", iConstraint); } } if (classConstraint != null) { output.Text += String.Format(" Base type constraint: {0}\r\n", tp.BaseType); } else output.Text += " Base type constraint: None\r\n";
Use the GenericParameterAttributes property to discover the special constraints on a type parameter, such as requiring that it be a reference type. The property also includes values that represent variance, which you can mask off as shown in the following code.
Dim sConstraints As GenericParameterAttributes = _ tp.GenericParameterAttributes And _ GenericParameterAttributes.SpecialConstraintMask
GenericParameterAttributes sConstraints = tp.GenericParameterAttributes & GenericParameterAttributes.SpecialConstraintMask;
The special constraint attributes are flags, and the same flag (GenericParameterAttributes.None) that represents no special constraints also represents no covariance or contravariance. Thus, to test for either of these conditions you must use the appropriate mask. In this case, use GenericParameterAttributes.SpecialConstraintMask to isolate the special constraint flags.
If sConstraints = GenericParameterAttributes.None Then output.Text &= " No special constraints." & vbCrLf Else If GenericParameterAttributes.None <> (sConstraints And _ GenericParameterAttributes.DefaultConstructorConstraint) Then output.Text &= " Must have a parameterless constructor." & vbCrLf End If If GenericParameterAttributes.None <> (sConstraints And _ GenericParameterAttributes.ReferenceTypeConstraint) Then output.Text &= " Must be a reference type." & vbCrLf End If If GenericParameterAttributes.None <> (sConstraints And _ GenericParameterAttributes.NotNullableValueTypeConstraint) Then output.Text &= " Must be a non-nullable value type." & vbCrLf End If End If
if (sConstraints == GenericParameterAttributes.None) { output.Text += " No special constraints.\r\n"; } else { if (GenericParameterAttributes.None != (sConstraints & GenericParameterAttributes.DefaultConstructorConstraint)) { output.Text += " Must have a parameterless constructor.\r\n"; } if (GenericParameterAttributes.None != (sConstraints & GenericParameterAttributes.ReferenceTypeConstraint)) { output.Text += " Must be a reference type.\r\n"; } if (GenericParameterAttributes.None != (sConstraints & GenericParameterAttributes.NotNullableValueTypeConstraint)) { output.Text += " Must be a non-nullable value type.\r\n"; } }
Constructing an Instance of a Generic Type
A generic type is like a template. You cannot create instances of it unless you specify real types for its generic type parameters. To do this at run time, using reflection, requires the MakeGenericType method.
To construct an instance of a generic type
Get a Type object that represents the generic type. The following code gets the generic type Dictionary<TKey, TValue> in two different ways: by using the Type.GetType(String) method overload with a string describing the type, and by calling the GetGenericTypeDefinition method on the constructed type Dictionary<String, Example> (Dictionary(Of String, Example) in Visual Basic). The MakeGenericType method requires a generic type definition.
' 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();
Construct an array of type arguments to substitute for the type parameters. The array must contain the correct number of Type objects, in the same order as they appear in the type parameter list. In this case, the key (first type parameter) is of type String, and the values in the dictionary are instances of a class named Example.
Dim typeArgs() As Type = _ { GetType(String), GetType(Example) }
Type[] typeArgs = {typeof(string), typeof(Example)};
Call the MakeGenericType method to bind the type arguments to the type parameters and construct the type.
Dim constructed As Type = _ d1.MakeGenericType(typeArgs)
Type constructed = d1.MakeGenericType(typeArgs);
Use the CreateInstance(Type) method overload to create an object of the constructed type. The following code stores two instances of the Example class in the resulting Dictionary<String, Example> object.
Dim o As Object = Activator.CreateInstance(constructed)
object o = Activator.CreateInstance(constructed);
Example
The following code example defines a DisplayGenericType method to examine the generic type definitions and constructed types that are used in the code and to display their information. The DisplayGenericType method shows how to use the IsGenericType, IsGenericParameter, and GenericParameterPosition properties and the GetGenericArguments method.
The example also defines a DisplayGenericParameter method to examine a generic type parameter and display its constraints.
The code example defines a set of test types, including a generic type that illustrates type parameter constraints, and shows how to display information about these types.
The example constructs a type from the Dictionary<TKey, TValue> class by creating an array of type arguments and calling the MakeGenericType method. The program compares the Type object that was constructed using MakeGenericType to a Type object that was obtained using typeof (GetType in Visual Basic), demonstrating that they are the same. Similarly, the program uses the GetGenericTypeDefinition method to obtain the generic type definition of the constructed type, and compares it to the Type object representing the Dictionary<TKey, TValue> class.
Imports System
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
' Makes the TextBlock available to all methods in Example.
Private Shared output As System.Windows.Controls.TextBlock
' The following method displays information about a generic
' type.
Private Shared Sub DisplayGenericType(ByVal t As Type)
output.Text &= vbCrLf & t.ToString() & vbCrLf
output.Text &= " Is this a generic type? " _
& t.IsGenericType & vbCrLf
output.Text &= " Is this a generic type definition? " _
& t.IsGenericTypeDefinition & vbCrLf
' Get the generic type parameters or type arguments.
Dim typeParameters() As Type = t.GetGenericArguments()
output.Text &= String.Format(" List {0} type arguments:" & vbCrLf, _
typeParameters.Length)
For Each tParam As Type In typeParameters
If tParam.IsGenericParameter Then
DisplayGenericParameter(tParam)
Else
output.Text &= String.Format(" Type argument: {0}" & vbCrLf, _
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)
output.Text &= String.Format(" Type parameter: {0} position {1}" & vbCrLf, _
tp.Name, tp.GenericParameterPosition)
Dim classConstraint As Type = Nothing
For Each iConstraint As Type In tp.GetGenericParameterConstraints()
If iConstraint.IsInterface Then
output.Text &= String.Format(" Interface constraint: {0}" & vbCrLf, _
iConstraint)
End If
Next
If classConstraint IsNot Nothing Then
output.Text &= String.Format(" Base type constraint: {0}" & vbCrLf, _
tp.BaseType)
Else
output.Text &= " Base type constraint: None" & vbCrLf
End If
Dim sConstraints As GenericParameterAttributes = _
tp.GenericParameterAttributes And _
GenericParameterAttributes.SpecialConstraintMask
If sConstraints = GenericParameterAttributes.None Then
output.Text &= " No special constraints." & vbCrLf
Else
If GenericParameterAttributes.None <> (sConstraints And _
GenericParameterAttributes.DefaultConstructorConstraint) Then
output.Text &= " Must have a parameterless constructor." & vbCrLf
End If
If GenericParameterAttributes.None <> (sConstraints And _
GenericParameterAttributes.ReferenceTypeConstraint) Then
output.Text &= " Must be a reference type." & vbCrLf
End If
If GenericParameterAttributes.None <> (sConstraints And _
GenericParameterAttributes.NotNullableValueTypeConstraint) Then
output.Text &= " Must be a non-nullable value type." & vbCrLf
End If
End If
End Sub
Public Shared Sub Demo(ByVal outputBlock As System.Windows.Controls.TextBlock)
' Makes the TextBlock available to all methods in Example.
output = outputBlock
' 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)
output.Text &= vbCrLf & _
"Compare types obtained by different methods:" & vbCrLf
output.Text &= " Are the constructed types equal? " _
& (d2.GetType() Is constructed) & vbCrLf
output.Text &= " Are the generic definitions equal? " _
& (d1 Is constructed.GetGenericTypeDefinition()) & vbCrLf
' 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
' This example produces output similar to the following:
'
'System.Collections.Generic.Dictionary`2[TKey,TValue]
' Is this a generic type? True
' Is this a generic type definition? True
' List 2 type arguments:
' Type parameter: TKey position 0
' Base type constraint: None
' No special constraints.
' Type parameter: TValue position 1
' Base type constraint: None
' No special constraints.
'
'System.Collections.Generic.Dictionary`2[System.String,SilverlightApplication.Example]
' Is this a generic type? True
' Is this a generic type definition? False
' List 2 type arguments:
' Type argument: System.String
' Type argument: SilverlightApplication.Example
'
'System.Collections.Generic.Dictionary`2[System.String,SilverlightApplication.Example]
' Is this a generic type? True
' Is this a generic type definition? False
' List 2 type arguments:
' Type argument: System.String
' Type argument: SilverlightApplication.Example
'
'Compare types obtained by different methods:
' Are the constructed types equal? True
' Are the generic definitions equal? True
'
'Test`1[T]
' Is this a generic type? True
' Is this a generic type definition? True
' List 1 type arguments:
' Type parameter: T position 0
' Interface constraint: SilverlightApplication.ITestArgument
' Base type constraint: None
' Must have a parameterless constructor.
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
{
// Makes the TextBlock available to all methods in Example.
private static System.Windows.Controls.TextBlock output;
// The following method displays information about a generic
// type.
private static void DisplayGenericType(Type t)
{
output.Text += String.Format("\r\n{0}\r\n", t);
output.Text += String.Format(" Is this a generic type? {0}\r\n",
t.IsGenericType);
output.Text += String.Format(" Is this a generic type definition? {0}\r\n",
t.IsGenericTypeDefinition);
// Get the generic type parameters or type arguments.
Type[] typeParameters = t.GetGenericArguments();
output.Text += String.Format(" List {0} type arguments:\r\n",
typeParameters.Length);
foreach( Type tParam in typeParameters )
{
if (tParam.IsGenericParameter)
{
DisplayGenericParameter(tParam);
}
else
{
output.Text += String.Format(" Type argument: {0}\r\n",
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)
{
output.Text += String.Format(" Type parameter: {0} position {1}\r\n",
tp.Name, tp.GenericParameterPosition);
Type classConstraint = null;
foreach(Type iConstraint in tp.GetGenericParameterConstraints())
{
if (iConstraint.IsInterface)
{
output.Text += String.Format(" Interface constraint: {0}\r\n",
iConstraint);
}
}
if (classConstraint != null)
{
output.Text += String.Format(" Base type constraint: {0}\r\n",
tp.BaseType);
}
else
output.Text += " Base type constraint: None\r\n";
GenericParameterAttributes sConstraints =
tp.GenericParameterAttributes &
GenericParameterAttributes.SpecialConstraintMask;
if (sConstraints == GenericParameterAttributes.None)
{
output.Text += " No special constraints.\r\n";
}
else
{
if (GenericParameterAttributes.None != (sConstraints &
GenericParameterAttributes.DefaultConstructorConstraint))
{
output.Text += " Must have a parameterless constructor.\r\n";
}
if (GenericParameterAttributes.None != (sConstraints &
GenericParameterAttributes.ReferenceTypeConstraint))
{
output.Text += " Must be a reference type.\r\n";
}
if (GenericParameterAttributes.None != (sConstraints &
GenericParameterAttributes.NotNullableValueTypeConstraint))
{
output.Text += " Must be a non-nullable value type.\r\n";
}
}
}
public static void Demo(System.Windows.Controls.TextBlock outputBlock)
{
// Makes the TextBlock available to all methods in Example.
output = outputBlock;
// 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);
output.Text += "\r\nCompare types obtained by different methods:\r\n";
output.Text += String.Format(" Are the constructed types equal? {0}\r\n",
(d2.GetType()==constructed));
output.Text += String.Format(" Are the generic definitions equal? {0}\r\n",
(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<>));
}
}
/* This example produces the following output:
System.Collections.Generic.Dictionary`2[TKey,TValue]
Is this a generic type? True
Is this a generic type definition? True
List 2 type arguments:
Type parameter: TKey position 0
Base type constraint: None
No special constraints.
Type parameter: TValue position 1
Base type constraint: None
No special constraints.
System.Collections.Generic.Dictionary`2[System.String,Example]
Is this a generic type? True
Is this a generic type definition? False
List 2 type arguments:
Type argument: System.String
Type argument: Example
System.Collections.Generic.Dictionary`2[System.String,Example]
Is this a generic type? True
Is this a generic type definition? False
List 2 type arguments:
Type argument: System.String
Type argument: Example
Compare types obtained by different methods:
Are the constructed types equal? True
Are the generic definitions equal? True
Test`1[T]
Is this a generic type? True
Is this a generic type definition? True
List 1 type arguments:
Type parameter: T position 0
Interface constraint: ITestArgument
Base type constraint: None
Must have a parameterless constructor.
*/
Compiling the Code
The code contains the C# using statements (Imports in Visual Basic) that are necessary for compilation.
No additional assembly references are required.
The code contains a static (Shared in Visual Basic) Demo method that has one parameter, a TextBlock that is used to display the output. For instructions on building the code as part of a simple Silverlight-based application, see Building Examples That Use a Demo Method and a TextBlock Control. You can put all the code in this example into one source file.
See Also