Reflection and Generics

I spent some time last week working on a tool we use internally to print out the C# “header file” view of assemblies.  We use it as part of the WinFX API reviews to give an overview of that the API looks like.  I am still in the middle of updating, but I do plan to post it when it is a bit more stable.   


The main thing I did was to add generic support.  This was pretty interesting as doing it gave me a really good idea of how the CLR and compilers actually work to create generic type. 


Consider if I have an assembly with the following two types.


public class List<T>  {


public class SortedList<T> where T : IComparable {




A quick ILDASM of the assembly shows me what the metadata really looks like:


.class public auto ansi beforefieldinit List<([mscorlib]System.Object) T>

       extends [mscorlib]System.Object


.class public auto ansi beforefieldinit SortedList<([mscorlib]System.IComparable) T>

       extends [mscorlib]System.Object



Notice the “type” of the type parameter, T?  This is how we include the constraints.. List can work over any type (all types both value and reference satisfy the constraint of being derived from System.Object.  Whereas sorted list will only work over types that implement the IComparable interface.  


Cool enough, but how do we get reflection to give us this data…  Once you understand the metadata layout it is not that bad…  See comments in line


      void WriteTypeConstraints(Type type)



            //Fist we loop through all the generic arguments (T) in our case

            foreach (Type t in type.GetGenericArguments())


                  //Then we find out what interfaces each of them implements...

                  Type[] arr = t.GetInterfaces();


                  //And what custom attributes it has (for the new constraint)

                  object[] arr2 = t.GetCustomAttributes(true);

                  //If there are any or there is a base type other than object then we

                  //have some constraints and therefore need to write out

                  //the where clause.

                  if (t.BaseType != typeof(object) || arr.Length+arr2.Length > 0)


                        Write(" where ");




                  //if there is a base type other than object, it counts as a

                  //constraint and needs to be written out

                  if (t.BaseType != typeof(Object))



                        //Find out if we need to write more out not..

                        if (arr.Length + arr2.Length > 0) Write(",");


                  //Here we write all the constraints for the interfaces

                  for (int i = 0; i < arr.Length; i++ )



                        if (i < arr.Length-1 || arr2.Length>0) Write(",");




                  //And here for the custom attributes

                  for (int i = 0; i < arr2.Length; i++)


                        //There is only one we use today, and that is for the

                        //"new" constraint.

                        if (arr2[i].GetType() ==









                        if (i < arr.Length - 1) Write(",");







Fairly simple, and it gives up something pretty in the end:


public class List<T>


      public List();



public class SortedList<T> where T : IComparable


      public SortedList();



What do you think?  Have you used reflection and generics?  What could be easier?

Comments (12)

  1. Steve Maine says:

    I did some experimentation with reflection and generics after the PDC. I noticed that Type now has an IsGenericParameter property, which gets set to true when you query a closed generic for its parameterizations.

    How does the value of the IsGenericParameter property impact equality comparisons on Type instances?

    That is, given

    List<MyType> foo;

    Type t1 = foo.GetType().GetGenericParameters()[0];

    t1 will have its IsGenericParameter property set to true, while the other Type instance won’t. Will t1 == typeof( MyType ) in Whidbey?

    For some reason, I had it in my head that the return values of different calls to typeof( Foo ) would always be reference-equal. This doesn’t seem to be the case, at least not in Whidbey. How is equality for Type instances implemented in a performant manner?

    FWIW, my original writeup can be found at:,guid,c8e940ae-c453-4d50-9c00-a1b8485bd5c7.aspx

  2. Steve Maine says:

    Oh, and it looks like generic parameters are now referred to as generic arguments…is that a post-PDC change?

  3. RichB says:

    Does your code also work on types which have a constructor constraint?

  4. Brad Abrams says:

    Rich — Yes, this code supports the new constraint…





  5. Mahavir says:

    Please help me with the questions below :

  6. Brad,

    Can you help me out with this problem? I’ve got some code that is dynamically compiled and loaded into an Assembly type. In the past, I could use myAssembly.CreateInstance to get an instance of a type in the Assembly. But what if the type I need to create requires a type argument? Is there any way to pass that through reflection to get an instance of the type?


  7. I ended up using BindGenericParameters:

    System.Type constructedType, genericType;

    genericType = compiled.CompiledAssembly.GetType(dynamicTypeName + "`1");

    constructedType = genericType.BindGenericParameters(new Type[1] {typeof(T)});

    comparer = constructedType.GetConstructor(new Type[0] {}).Invoke(null)

    as System.Collections.Generic.IComparer<T>;

    I am wondering why I have to add the "`1" at the end of my type name to get the generic. I can see that it indicates the number of type parameters, but the example for BindGenericParameters in the docs didn’t, IIRC, add that (so its code shouldn’t work). Are you guys going to work around this or is this the format you’re sticking with?

  8. Joel Pobar says:

    Backtick "`" plus integer specifies the arity of the Generic type, and is actually burned in at the metadata level as the string type name. GetType() takes an unmangled string name and simply brings it to life by string comparing over the metadata table. It’s unfortunate that we couldn’t use angle brackets to specify arity, ala C# syntax, but the C++ folk have already reserved them in the type name grammar. 🙂

    For now, you’ll need to specify the string name according to the type name grammar rules (which should be specified in the next revision of the ECMA specification). Which means, Foo`1 for Foo<T>, Foo`2 for Foo<K,V> etc. We may look at adding helper methods for string name mangling sometime in the future.

  9. Thanks, Joel. I suppose that once you’re aware of it, it’s not a big deal, but it did throw me for a loop, especially since the BindGenericParameters example in the current docs didn’t have that. I had to go into debug to figure out what the type name actually was.

    It would be nice to have it do some sort of search if no arity is indicated, e.g.:

    1. Look for a non-generic match first.

    2. Look for generic match, going from 1-n arity, matching the first found.

    Granted, this might cause more confusion than it’s worth, but as long as this or the current format is documented, we’ll probably be okay.

    Just curious, do you find or expect much overloading on arity?

Skip to main content