BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Reflection
.NET 2.0+

Reflecting Generic Type Information

The fifteenth part of the Reflection tutorial describes reflection techniques for obtaining information about generic types. The article looks at some of the Type members introduced in the .NET framework version 2.0 that are specific to generic types.

Examining a Generic Type's Type Parameters

A key reflection operation with generic types is obtaining details of the generic type arguments. This is achieved with the GetGenericArguments method. The method returns an array of Type objects with one item in the array for each type parameter. The parameter order and the returned array item order are the same.

In the code below, the type arguments for a KeyValuePair are obtained. The contents of the resultant array are displayed in the comment.

Type[] pTypes = typeof(KeyValuePair<int, string>).GetGenericArguments();

/* TYPES

int
string

*/

You would not normally use the GetGenericArguments method against a non-generic type. However, if you do, you will find that the resultant array is empty.

Type[] pTypes = typeof(string).GetGenericArguments();  // Empty array

You can use GetGenericArguments against open and closed constructed types and for generic type definitions. This means that the Type objects in the array may represent assigned types or generic type parameters. To determine which, you can check the IsGenericParameter property, which is true for unassigned type parameters and false when the type has been fixed.

In the sample code below, the first reflected type has the type parameter omitted to make it a generic type definition. The second is a closed constructed type.

bool generic;
generic = typeof(List<>).GetGenericArguments()[0].IsGenericParameter;        // true
generic = typeof(List<string>).GetGenericArguments()[0].IsGenericParameter;  // false

The final property we'll look at for examining the type parameters of a generic type is GenericParameterPosition. As the name may suggest, this returns an integer specifying the zero-based position where the parameter appears in the type's argument list. In the examples we've been using this value is obvious, as it matches the index in the array returned by GetGenericArguments. However, when you are working with arguments individually, for example in a foreach loop, this ordering property can be invaluable.

Type type = typeof(KeyValuePair<,>);
Type firstParam = type.GetGenericArguments()[0];
Type secondParam = type.GetGenericArguments()[1];
int firstPos = firstParam.GenericParameterPosition;    // 0
int secondPos = secondParam.GenericParameterPosition;  // 1

Creating a Closed Type from a Generic Type Definition

When you have a generic type definition, you may want to convert it into a closed constructed type, supplying the types for each type argument. This is useful when you are instantiating generic objects at runtime; something we'll look at later in the tutorial. For now we'll look at the process for creating a closed type's Type object from a generic type definition, which is achieved using the MakeGenericType method.

MakeGenericType accepts an array of Type objects that contains the types that you wish to assign to the type arguments. The parameter is defined as a parameter array, so you can pass a previously constructed array or a comma-separated list of types.

The following sample code demonstrates the use of MakeGenericType. Here we start by initialising the gtd variable, which represents a generic type definition for the List class. Note that the type argument is not assigned. Next, MakeGenericType is used to create a Type instance for a closed constructed type. The resultant Type represents List<string>. To show the difference between the two objects, the name of the first, and only, type argument is obtained.

Type gtd = typeof(List<>);
Type made = gtd.MakeGenericType(typeof(string));
string gtdParam = gtd.GetGenericArguments()[0].Name;    // T
string madeParam = made.GetGenericArguments()[0].Name;  // String

Obtaining the Generic Type Definition for a Type

A reverse operation to MakeGenericType is possible using the GetGenericTypeDefinition method. This can be executed against any generic type to generate a new Type instance containing the generic type definition for the type. If executed against an open or closed constructed type, the result is a similar type containing only generic type parameters. If executed against a generic type definition, the method returns a matching type definition.

Type type = typeof(List<string>);
Type gtd = type.GetGenericTypeDefinition();
string madeParam = type.GetGenericArguments()[0].Name;  // String
string gtdParam = gtd.GetGenericArguments()[0].Name;    // T
16 June 2012