Ayende @ Rahien

It's a girl

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.

Comments

Marcos
10/29/2007 08:56 PM by
Marcos

Hi there

I was using the Dynamic Methods for the FileHelpers and are awesome, there are a lot of libraries that simply the process.

This is one of the most hidden and wonderful features of .NET 2.0

http://blog.filehelpers.com/2007/01/improving-filehelpers-performance-now.html

I think that worth a lot the extra effort and if you cache (like you said) the delegate you are done =)

The performance gain is incredible !!

Cheers

Omer van Kloeten
10/29/2007 09:05 PM by
Omer van Kloeten

You could also use CodeDom to generate this. It would be easier and more readable, but will take longer during the first run.

Ayende Rahien
10/29/2007 09:08 PM by
Ayende Rahien

Omer,

Yes, but dynamic methods can skip visibility calls, so that is a significant advantage.

Tim B
10/29/2007 09:21 PM by
Tim B

Regarding reflection based wrappers, check out RunSharp - http://www.codeproject.com/dotnet/runsharp.asp

Avish
10/29/2007 09:28 PM by
Avish

Boo does some pretty neat things with Dynamic Methods to allow fast duck-typing.

Niki
10/30/2007 09:46 AM by
Niki

IronPython can compile to dynamic methods, that's a very easy way to create code on the fly.

Omer: Using CodeDom has several disadvantages, worst of them is probably that the generated code is never unloaded or collected by the GC.

Morten Lyhr
10/30/2007 11:00 AM by
Morten Lyhr

I think reading MSIL makes my eyes hurt!

But it is very useful, especially if the code it generates is unit tested, and is isolated.

I have created a dynamic composite factory here:

http://morten.lyhr.dk/PermaLink,guid,aa797b7c-a418-45c0-9510-61dc395d7c2d.aspx

Its not done via DynamicMethod, it creates a whole new class, but MSIL is MSIL. I got it working by creating what i wanted in C#, compiled it to and assembly and opened it in reflector.

Is there a smarter way to do this?

Ayende Rahien
10/30/2007 11:07 AM by
Ayende Rahien

Morten,

that is what I usually do as well :-)

Jeremy
10/30/2007 03:50 PM by
Jeremy

IL generation and developer productivity should never coexist in the same sentence.

Why fight with IL if we can just move over to a dynamic language where you write these kind of runtime extensions in the language itself? If we could do this in Ruby instead, Metaprogramming extensions are well within the reach of mere mortal developers and far simpler mechanically.

Nick
10/30/2007 05:01 PM by
Nick

I wrote a pretty cool template language that compiled templates into dynamic methods. It's a huge performance win when you know that your code is going to be reusing the same template over and over. Being able to skip visibility checks was especially nice, since it allowed the templates to call helper methods on an internal static class. This allowed me to write as much code as possible in C#, and then "glue" it together using dynamically generated IL.

Thomas Danecker
10/30/2007 08:40 PM by
Thomas Danecker

I was using dynamic methods to dispatch intercepted method calls for a log service (the typical AOP application). They are very, very efficient (the JIT compilation is damn fast, especially compared to reflection). You may check out my blog post: http://tdanecker.blogspot.com/2007/09/interception-with-proxies.html

Morten Lyhr
11/09/2007 09:16 AM by
Morten Lyhr

Ayende

It can be done a little bit smarter.

Look at thsi plug-in for Reflector.

http://www.codeplex.com/reflectoraddins/Wiki/View.aspx?title=ReflectionEmitLanguage&referringTitle=Home

I made a post about it here:

http://morten.lyhr.dk/PermaLink,guid,a844104f-949a-4800-828c-1fde0fc711c1.aspx

Comments have been closed on this topic.