I wrote my "hello, world" program for .NET 2.0. I wanted to see how reflection worked with generic types, so I wrote some code that reverses a dictionary. That is, it takes a Dictionary that maps keys to values and returns a Dictionary whose keys are the original values and the values are the original keys.
First off, some definitions: Generic types come in two flavors, open and closed. An open generic type is what you get when your write a definition for a generic type or a generic method. An open generic has as part of its definition placeholders for types that will get filled in later when the type is instantiated (much like the way a regular method has some parameters whose values get filled in when that method is actually called). A closed generic type is an instantiation of an open generic type, which is what you get when you actually bind values to an open generic. It's what you get when you declare a variable to be a
ListOk, enough theory. There's some significant additions to the Reflection API's to support generics in Whidbey. First off,
System.Type and System.Reflection.MethodInfo now support a property called HasGenericParameters, which returns true if a type or method is generic. There's also a related property called HasUnboundGenericParameters which will tell you if a type is an open or closed generic.The only way you can actually get your hands on an open generic type at runtime is to call the
GetGenericTypeDefinition() method on the type of the closed generic. This is how you can convert from typeof( DictionaryGiven a closed generic type, you can determine the types to which the generic parameters are bound by calling the
GetGenericParameters() method. This gives you back an array of System.Type instances that are positionally related to the types of the parameters. So if you do a GetGenericParameters on typeof( SomeClass{ typeof( int ), typeof( string ), typeof( float ) }.
You can convert an open generic to a closed generic by calling
BindGenericParameters() and passing it a type array. Like GetGenericParameters, this array is parallel to the generic parameter list. Thus, you can convert a typeof( SomeClass< T, U, V > ) to a typeof( SomeClass< int, string, float > ) by calling BindGenericParameters( new Type[]{ typeof(int), typeof(string), typeof(float) } ).Once you have a closed generic type hanging around, you can get an instance of that closed generic in the normal reflection way -- by calling
Activator.CreateInstance(). Nothing magical here.There are a couple of other methods hanging around System.Type that have to do with generics, but I didn't have any immediate use for them.
In summary:
-- System.Type and System.MethodInfo now have a HasGenericParameters property
-- You can convert can convert a closed generic to an open generic by calling GetGenericTypeDefinition()
-- You can convert an open generic to a closed generic by calling BindGenericParameters()
-- You can instantiate a closed generic with Activator.CreateInstance()
Here's the code for ReverseDictionary
public
static Dictionary{
Type openOriginal = originalType.GetGenericTypeDefinition();
Type[] typeParameters = originalType.GetGenericParameters();
Debug.Assert( typeParameters.Length == 2 );
Type keyType = typeParameters[0];
Debug.Assert( false == keyType.IsGenericParameter );
Type valueType = typeParameters[1];
Debug.Assert( false == valueType.IsGenericParameter );
Type reverseDictType = openOriginal.BindGenericParameters( new Type[]{ valueType, keyType } );
Debug.Assert( true == reverseDictType.HasGenericParameters );
Debug.Assert( false == reverseDictType.HasUnboundGenericParameters );
Dictionary
//We could have just said
//Dictionary
{
V val = original[key];
reverse[val] = key;
}
return reverse;
}
GenericReflection.cs.txt (2.37 KB)
