Reflection and Generic Types
From the point of view of reflection, the difference between a generic type and an ordinary type is that a generic type has associated with it a set of type parameters (if it is a generic type definition) or type arguments (if it is a constructed type). A generic method differs from an ordinary method in the same way.
There are two keys to understanding how reflection handles generic types and methods:
The type parameters of generic type definitions and generic method definitions are represented by instances of the Type class.
Many properties and methods of Type have different behavior when a Type object represents a generic type parameter. These differences are documented in the property and method topics. For example, see IsAutoClass and DeclaringType. In addition, some members are valid only when a Type object represents a generic type parameter. For example, see GetGenericTypeDefinition.
If an instance of Type represents a generic type, then it includes an array of types that represent the type parameters (for generic type definitions) or the type arguments (for constructed types). The same is true of an instance of the MethodInfo class that represents a generic method.
For example code demonstrating the methods discussed here, see How to: Examine and Instantiate Generic Types with Reflection.
The following discussion assumes familiarity with the terminology of generics, such as the difference between type parameters and arguments and open or closed constructed types. For more information, see Generics.
This overview consists of the following sections:
When you use reflection to examine an unknown type, represented by an instance of Type, use the IsGenericType property to determine whether the unknown type is generic. It returns
true if the type is generic. Similarly, when you examine an unknown method, represented by an instance of the MethodInfo class, use the IsGenericMethod property to determine whether the method is generic.
Use the IsGenericTypeDefinition property to determine whether a Type object represents a generic type definition, and use the IsGenericMethodDefinition method to determine whether a MethodInfo represents a generic method definition.
Generic type and method definitions are the templates from which instantiable types are created. Generic types in the .NET Framework class library, such as Dictionary<TKey, TValue>, are generic type definitions.
A generic type or method is closed if instantiable types have been substituted for all its type parameters, including all the type parameters of all enclosing types. You can only create an instance of a generic type if it is closed. The Type.ContainsGenericParameters property returns
true if a type is open. For methods, the MethodInfo.ContainsGenericParameters method performs the same function.
If you have an open generic type or method that is not a generic type or method definition, you cannot create instances of it and you cannot supply the type parameters that are missing. You must have a generic type or method definition. Use the GetGenericTypeDefinition method to obtain the generic type definition or the GetGenericMethodDefinition method to obtain the generic method definition.
For example, if you have a Type object representing
Dictionary<int, string> (
Dictionary(Of Integer, String) in Visual Basic) and you want to create the type
Dictionary<string, MyClass>, you can use the GetGenericTypeDefinition method to get a Type representing
Dictionary<TKey, TValue> and then use the MakeGenericType method to produce a Type representing
For an example of an open generic type that is not a generic type, see "Type Parameter or Type Argument" later in this topic.
Use the Type.GetGenericArguments method to obtain an array of Type objects that represent the type parameters or type arguments of a generic type, and use the MethodInfo.GetGenericArguments method to do the same for a generic method.
Once you know that a Type object represents a type parameter, there are many additional questions reflection can answer. You can determine the type parameter's source, its position, and its constraints.
To determine whether a particular element of the array is a type parameter or a type argument, use the IsGenericParameter property. The IsGenericParameter property is
true if the element is a type parameter.
A generic type can be open without being a generic type definition, in which case it has a mixture of type arguments and type parameters. For example, in the following code, class
D derives from a type created by substituting the first type parameter of
D for the second type parameter of
A generic type parameter might come from the type you are examining, from an enclosing type, or from a generic method. You can determine the source of the generic type parameter as follows:
First, use the DeclaringMethod property to determine whether the type parameter comes from a generic method. If the property value is not a null reference (
Nothingin Visual Basic), then the source is a generic method.
If the source is not a generic method, use the DeclaringType property to determine the generic type the generic type parameter belongs to.
If the type parameter belongs to a generic method, the DeclaringType property returns the type that declared the generic method, which is irrelevant.
In rare situations, it is necessary to determine the position of a type parameter in the type parameter list of its declaring class. For example, suppose you have a Type object representing the
B<int, V> type from the preceding example. The GetGenericArguments method gives you a list of type arguments, and when you examine
V you can use the DeclaringMethod and DeclaringType properties to discover where it comes from. You can then use the GenericParameterPosition property to determine its position in the type parameter list where it was defined. In this example,
V is at position 0 (zero) in the type parameter list where it was defined.
Use the GetGenericParameterConstraints method to obtain the base type constraint and interface constraints of a type parameter. The order of the elements of the array is not significant. An element represents an interface constraint if it is an interface type.
To determine whether a type parameter is covariant or contravariant, apply the GenericParameterAttributes.VarianceMask mask to the GenericParameterAttributes value that is returned by the GenericParameterAttributes property. If the result is GenericParameterAttributes.None, the type parameter is invariant. See Covariance and Contravariance.
To determine the special constraints of a type parameter, apply the GenericParameterAttributes.SpecialConstraintMask mask to the GenericParameterAttributes value that is returned by the GenericParameterAttributes property. If the result is GenericParameterAttributes.None, there are no special constraints. A type parameter can be constrained to be a reference type, to be a non-nullable value type, and to have a default constructor.
|How to: Examine and Instantiate Generic Types with Reflection||Shows how to use the properties and methods of Type and MethodInfo to examine generic types.|
|Generics||Describes the generics feature and how it is supported in the .NET Framework.|
|How to: Define a Generic Type with Reflection Emit||Shows how to use reflection emit to generate generic types in dynamic assemblies.|
|Viewing Type Information||Describes the Type class and provides code examples that illustrate how to use Type with various reflection classes to obtain information about constructors, methods, fields, properties, and events.|