Share via


C#: Generic Type Parameters And Dynamic Types

Introduction

There may be times when you need to use some type in your application that is not known until run time. This post will explain what you need to do in order to be able to use such a dynamically loaded type from a dynamically loaded assembly as a generic type parameter when you create an instance of some generic class in your application.

Generics

It should be clear that a generic class is like a template or blueprint for a type and that a developer that aims to use the class must specify a type inside the angle brackets when creating an instance of the generic class. If you want to learn more about generic types themselves, read the chapter on generic type parameters in the C# programming guide on MSDN which is available here.

Now, if you try to create an instance of a generic class, like for example a List<T>, and simply set its type parameter to some Type variable that has been created at run time, you won’t be able to compile your application.

For example, consider the following (erroneous) code where we try to create a List<T> and set its type argument to a type called “SomeCustomClass” that was defined in a namespace called “SomeCustomNamespace” in a dynamically loaded assembly called “SomeCustomAssembly.dll”: 

//load the assembly where the type is defined
Assembly assembly = Assembly.LoadFrom(@"C:\Users\magnus\SomeCustomAssembly.dll");

//get the type
Type customType = assembly.GetType("SomeCustomNamespace.SomeCustomClass");
/* ! THIS WILL NOT COMPILE ! */
List<customType> objects = new  List<customType>();

You cannot do this. After all, the main purpose of generics is to provide compile-time type safety as fixing compile-time errors is usually a lot easier than finding and fixing errors that occur in run time.

Type.MakeGenericType

So how can you create a List<T>, or any other generic type for that matter, that contains objects of a type that is unknown when you compile the application? Luckily, there is a MakeGenericType method in the System.Type class that you can use to create the actual List<SomeCustomClass> type dynamically:

//load the assembly where the type is defined
Assembly assembly = Assembly.LoadFrom(@"C:\Users\magnus\SomeCustomAssembly.dll");
//get the type
Type customType = assembly.GetType("SomeCustomNamespace.SomeCustomClass");
//create the actual List<customType> type
Type genericListType = typeof(List<>);
Type customListType = genericListType.MakeGenericType(customType);

You could then use the static System.Activator.CreateInstance method – this method creates an instance of the specified type using that type’s default constructor – to create an instance of the customListType above:

IList customListInstance = (IList)Activator.CreateInstance(customListType);

This will create a List<T> that can only contain objects of the dynamically loaded type. If you call the GetType() method on this list instance during a debug session in Visual Studio, you will see that it is actually a List<SomeCustomClass>:

https://magnusmontin.files.wordpress.com/2014/10/customlist.png?w=735&h=132

Since the Activator.CreateInstance returns an object, the result is cast to an IList which is an interface that is implemented by the generic List<T> class. Whenever you want to add some SomeCustomClass item to the list, you simply create an instance of the dynamic type using the Activator.CreateInstance method and add it to the list using the Add method:

object someCustomClassInstance = Activator.CreateInstance(customType);
customListInstance.Add(someCustomClassInstance);

Note that if you try to add an object of any other type than SomeCustomClass in this case, it will result in a System.ArgumentException since the customListInstance is really a List<SomeCustomClass> that only accepts SomeCustomClass objects.

Type safety

It is important to realize that you won’t get any kind of compile-time checking when using a dynamic type like this. For example, the following code would compile just fine, but always result in a runtime error when being run since it tries to add a string to a List<SomeCustomClass>:

IList customListInstance = (IList)Activator.CreateInstance(customListType);
  
object someCustomClassInstance = Activator.CreateInstance(customType);
customListInstance.Add(someCustomClassInstance);
  
string someString = "abc";
/* ! This will result in a System.ArgumentException ! */
customListInstance.Add(someString);

Therefore, you should only use dynamic types when you are required to do so for some specific reason. If you know exactly which assemblies and types you are going to use beforehand, you should add a reference to the assembly and use the types in it as usual. Except for type safety, there is obviously also some performance penalties associated with creating types and objects dynamically.