Ayende @ Rahien

Hi!
My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:

ayende@ayende.com

+972 52-548-6969

, @ Q c

Posts: 5,953 | Comments: 44,411

filter by tags archive

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

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

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

Omer,

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

Tim B

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

Avish

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

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

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

Morten,

that is what I usually do as well :-)

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

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

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

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

Comment preview

Comments have been closed on this topic.

FUTURE POSTS

No future posts left, oh my!

RECENT SERIES

  1. The RavenDB Comic Strip (3):
    28 May 2015 - Part III – High availability & sleeping soundly
  2. Special Offer (2):
    27 May 2015 - 29% discount for all our products
  3. RavenDB Sharding (3):
    22 May 2015 - Adding a new shard to an existing cluster, splitting the shard
  4. Challenge (45):
    28 Apr 2015 - What is the meaning of this change?
  5. Interview question (2):
    30 Mar 2015 - fix the index
View all series

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats