Friday, 18 April 2014

Calling generic methods with runtime Type parameters

In the normal course of events, a call to a generic method needs to have its type resolved at compile time. For example, consider this class and method:
class TypeWriter
{
    public void WriteType<T>(TextWriter target)
    {
        target.WriteLine("T is {0}"typeof(T));
    }
}
This generic method needs to be called with its type parameter resolved at runtime, like this:
var typeWriter = new TypeWriter();
typeWriter.WriteType<Program>(Console.Out);
which gives this output:


But what do you do if you only discover the types at runtime so don't know the types at compile time? This commented code wouldn't compile because the variable assemblyType can't be resolved to a generic parameter:
foreach (var assemblyType in Assembly.GetExecutingAssembly().GetTypes())
{
    // typeWriter.WriteType<assemblyType>(Console.Out);
}

This is where System.Reflection comes in. The MethodInfo class has a method MakeGenericMethod that takes an array of System.Type, substitutes the method's generic parameters for the arguments and returns a new MethodInfo instance. This new MethodInfo instance can then be invoked like any other. Here's how this looks in code:
foreach (var assemblyType in Assembly.GetExecutingAssembly().GetTypes())
{
    // Get a handle on the method to call
    var method = typeof(TypeWriter).GetMethod("WriteType");

    // Pass the type parameter(s)
    var genericMethod = method.MakeGenericMethod(assemblyType);

    // Call the method on the TypeWriter instance, passing parameter(s)
    genericMethod.Invoke(typeWriter, new[] { Console.Out });
}
This gives the output: