Again on Expression Tree vs Reflection

In last post Expression Tree vs Reflection I showed how to use Expression Tree to dynamically build a function object at runtime  that you can use to invoke methods of unknown objects. This is a peculiar use of Expression Tree, but you can obtain the same result with Lightweight Code Generation (as some people commented in the post). Moreover the LCG approach is probably faster because the expression tree uses LCG in the Compile method, so if you directly generate your code in IL, there is no need of intermediate Expression Tree object. (You have also full control on IL). Remember that when I say that LCG is faster, I’m speaking about the time needed to build the dynamic function, and not the real time needed to invoke the function. To compare the two techniques here is an example, I want to be able to write code like this.

Func<Object, Int32> func = ExpressionTreeReflection.ReflectFunction<Int32>(suType, "AMethod"); Assert.That(func(suInstance), Is.EqualTo(1));

I have a type that is unknown at compile time, I know that it has a method called AMethod, and I want to create a Func<Object, Int32> object to dynamically invoke that method instead of invoking it with plane reflection. Here it is a possible implementation of ReflectFunction with Expression Tree:

1 public static Func<Object, T> ReflectFunction<T>(Type objType, String methodName) 2 { 3 MethodInfo minfo = objType.GetMethod( 4 methodName, 5 BindingFlags.Instance | BindingFlags.Public, 6 null, 7 CallingConventions.Any, 8 new Type[] { }, 9 null); 10 ParameterExpression param = Expression.Parameter(typeof(Object), "object"); 11 Expression convertedParamo = Expression.Convert(param, objType); 12 Expression invoke = Expression.Call(convertedParamo, minfo); 13 LambdaExpression lambda = Expression.Lambda(invoke, param); 14 Expression<Func<Object, T>> dynamicSetterExpression = (Expression<Func<Object, T>>)lambda; 15 return dynamicSetterExpression.Compile(); 16 }

It is really straightforward to write, first of all get the MethodInfo object for the method you want to invoke, then create a parameter of type Object, then a conversion parameter to cast the object to the correct type (line 11) and finally the expression representing the call to the method. To obtain a Func<Object, T> object I need to create a lambda expression, cast it to the appropriate type, and finally call its Compile method. With LCG the code to obtain the same result is the following.

1 public static Func<Object, T> ReflectFunction<T>(Type objType, String methodName) 2 { 3 MethodInfo minfo = objType.GetMethod( 4 methodName, 5 BindingFlags.Instance | BindingFlags.Public, 6 null, 7 CallingConventions.Any, 8 new Type[] { }, 9 null); 10 DynamicMethod retmethod = new DynamicMethod( 11 objType.FullName + methodName, 12 typeof (T), 13 new [] {typeof(Object)}); 14 ILGenerator ilgen = retmethod.GetILGenerator(); 15 ilgen.Emit(OpCodes.Ldarg_0); 16 ilgen.Emit(OpCodes.Castclass, objType); 17 ilgen.Emit(OpCodes.Callvirt, minfo); 18 ilgen.Emit(OpCodes.Ret); 19 return (Func<Object, T>) retmethod.CreateDelegate(typeof(Func<Object, T>)); 20 }

The code is not complex, but we need to know IL to make it works.  After I grab the MethodInfo object I create a DynamicMethod with the constructor that accepts the name of the method, the return type and the list of parameters types. Then you can call the GetILGenerator method, and you will obtain a ILGenerator object that you can use to write IL code into the new method body. The IL code is really simple, since the dynamic method will be generated as is a static method (check the documentation to see how to dynamically create an instance method) the first argument is the object passed to the function, so I use Ldarg_0 to push on the stack, then a Castclass to be sure that the caller passed an object of the correct type, and finally the Callvirt to actually invoke the right method, now the return value is on the stack, so you can call Ret. The final touch is calling CreateDelegate method of the DynamicMethod specifying the signature of the function, and the game is done.

For those interested in performance, here is a simple test

[Test, Explicit] public void TestPerformanceGain() { Func<Object, Int32> func = ExpressionTreeReflection.ReflectFunction<Int32>(suType, "AMethod"); Func<Object, Int32> lcgfunc = LCGReflection.ReflectFunction<Int32>(suType, "AMethod"); MethodInfo minfo = suType.GetMethod("AMethod", BindingFlags.Public | BindingFlags.Instance); Double RefDuration = With.PerformanceCounter(() => { for (Int32 I = 0; I < 100000; ++I) minfo.Invoke(suInstance, new Object[] { }); }); Double ExpDuration = With.PerformanceCounter(() => { for (Int32 I = 0; I < 100000; ++I) func(suInstance); }); Double LcgDuration = With.PerformanceCounter(() => { for (Int32 I = 0; I < 100000; ++I) lcgfunc(suInstance); }); Console.WriteLine("Reflection = {0} Expression Tree {1} LCG {2}", RefDuration, ExpDuration, LcgDuration); }

And the corresponding output.

Reflection = 0.892017037086468 Expression Tree 0.012591549690529 LCG 0.0127834533958392

As you can see the Expression Tree method seems to be a little faster, but the timing is quite the same. The real thing to notice is that both techniques are really faster than invoking the method through the MethodInfo object.



DotNetKicks Image

Published by

Ricci Gian Maria

.Net programmer, User group and community enthusiast, programmer - aspiring architect - and guitar player :). Visual Studio ALM MVP

One thought on “Again on Expression Tree vs Reflection”

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.