Dynamic Methods
I don't hear it talked about, but the CLR has a very efficient way to generate code at runtime. Probably this is because this code generation stuff is something that is accessible through IL generation only, and that is not for the faint of heart. Nevertheless, there are some very useful uses for this. NHibernate is utilizing this approach to avoid the costs of reflection, for instance.
Let us take a look about a simple scenario, we want to translate any delegate type with two parameters to a call to an instance method on our class:
public class Program
{
private static void Main(string[] args)
{
new Program().Execute();
}
private void Execute()
{
//instance that has events that we want to subscribe the adapter to
DataGridView dataGridView1 = new DataGridView();
EventInfo ei = dataGridView1.GetType().GetEvent("RowPrePaint");
ParameterInfo[]pia = ei.EventHandlerType.GetMethod("Invoke").GetParameters();
MethodInfo methodInfo = this.GetType().GetMethod("Handler",
new Type[]{typeof (object), typeof (object)});
DynamicMethod mtd = new DynamicMethod(
"Adapter",
typeof(void),
new Type[]
{
typeof (Program), // this
pia[0].ParameterType,// sender
pia[1].ParameterType // e
}, this.GetType(), true);
ILGenerator gtr = mtd.GetILGenerator();
gtr.Emit(OpCodes.Ldarg_0); // this
gtr.Emit(OpCodes.Ldarg_1); // sender
gtr.Emit(OpCodes.Ldarg_2); // e
gtr.Emit(OpCodes.Call, methodInfo);
gtr.Emit(OpCodes.Ret);
// generate a delegate bound to this object instance
Delegate dynamicDelegate = mtd.CreateDelegate(typeof(DataGridViewRowPrePaintEventHandler), this);
//register the adapter
ei.AddEventHandler(dataGridView1, dynamicDelegate);
dataGridView1.GetType().GetMethod("OnRowPrePaint", BindingFlags.NonPublic | BindingFlags.Instance)
.Invoke(dataGridView1, new object[] { null });
}
// method that handles the call
public void Handler(object x, object y)
{
Console.WriteLine("{0}: {1}, {2}", this.GetHashCode(), x, y);
}
}
Take into account that you are probably going to want to cache the method anyway, but this is a cool, if long winded way of achieving this. Personally, in this scenario I would probably simply write a reflection based wrapper, the complexity doesn't really have justification in such a case, but this is just an example, of course.