Thursday, March 25, 2010

Dynamic constructor invocation - based on Timwi's dynamic method invocation

This is an addition to Timwi's excellent post: Dynamic method invocation without the TargetInvocationException wrapping.

What I find it useful for:

    When you write a program that invokes methods through delegate's "Invoke" function, debugger does not break on place where that exception is thrown in invoked method, it breaks on "Invoke" function, with original exception wrapped as InnerException of TargetInvocationException.
    Timwi's approach solves that problem (debugger break position is in the invoked method, and there is no exception wrapping)

What is changed:
  • made some modifications so it can be compiled for .Net 2.0
  • InvokeDirect renamed to Invoke
  • added Invoke overload that invokes constructor by ConstructorInfo
  • (details can be seen in source, search for "Quazistax" in comments)
Basic idea behind implementation:
  • For each new constructor signature, dynamically create class with static method that returns object created using "new" on desired ConstructorInfo, and cache that method in dictionary with provided ConstructorInfo as key.
e.g. for Form parameterless constructor we dynamically create something like this:
public class FormConstructorGeneratedClass
{
    public static Form Construct()
    {    return new Form();    }
}
Dynamically creating method that calls constructor with specified signature:
private static MethodInfo createConstructorMethod(ConstructorInfo con, string sig)
{
    var typeBuilder = modBuilder.DefineType("construct " + sig + ".GeneratedClass",
        TypeAttributes.Public,
        typeof(object));

    // Create a Construct method that creates new object trough given constructor
    var methodBuilder = typeBuilder.DefineMethod("Construct",
       MethodAttributes.Public | MethodAttributes.Static,
       con.DeclaringType, getParameterTypes(con));

    // Now generate IL which will do constructing.
    // Generated IL is equivalent to the following single line of C# code:
    // return new ConstructedType(parameters[0],  parameters[1], ...);
    // assuming that ConstructedType is type for which ConstructorInfo is given
    var il = methodBuilder.GetILGenerator();
    ParameterInfo[] parameters = con.GetParameters();
    for (int i = 0; i < parameters.Length; ++i)
        EmitLdarg(il, i);

    il.Emit(OpCodes.Newobj, con); //calling constructor
    il.Emit(OpCodes.Ret);

    return typeBuilder.CreateType().GetMethod("Construct");
}
  • When invoking constructor, get from cache method created in step before and invoke it through Timwi's approach
Source code:
You can get the source here.

No comments:

Post a Comment