Everyone knows that invoking method through reflection is slower than direct invocation, here is a little test.
Int32 iterations = 100000; Stopwatch watch = new Stopwatch(); MyObject obj = new MyObject(); obj.Prop = 0; watch.Start(); for (Int32 I = 0; I < iterations; ++I) { obj.Prop = obj.Prop + 1; } watch.Stop(); Console.WriteLine("Direct invocation {0} iterations {1} ms", iterations, watch.ElapsedMilliseconds); PropertyInfo pinfo = typeof(MyObject).GetProperty("Prop", BindingFlags.Public | BindingFlags.Instance); obj.Prop = 0; Object[] nullobj = new Object[] { }; watch.Reset(); watch.Start(); for (Int32 I = 0; I < iterations; ++I) { pinfo.SetValue( obj, ((Int32)pinfo.GetValue(obj, nullobj)) + 1, nullobj); } watch.Stop(); Console.WriteLine("Reflection invocation {0} iterations {1} ms", iterations, watch.ElapsedMilliseconds);
This snippet creates an object with an int property, then it make a simple increment of the property, the first time with standard code, the second time with reflection, every iteration needs two invocation through reflection, one to get the actual value, the other to set the new value, here is the output.
Direct invocation 100000 iterations 2 ms
Reflection invocation 100000 iterations 1307 ms
This simple example shows that reflection is really, really slower, but reflection makes possible to modify a property whose name is known only at runtime, so it is unavoidable in certain situation.
A simple alternative approach exists, it relay on using Expression Trees. For those who does not knows Expression Trees I suggest reading this book, in short an expression tree is simple a way to represent an expression through an object model. Now lets look at this code.
1 MethodInfo SetterMethodInfo = pinfo.GetSetMethod(); 2 ParameterExpression param = Expression.Parameter(typeof(MyObject), "param"); 3 Expression GetPropertyValueExp = Expression.Lambda( 4 Expression.Property(param, "Prop"), param); 5 Expression<Func<MyObject, Int32>> GetPropertyValueLambda = 6 (Expression<Func<MyObject, Int32>>)GetPropertyValueExp; 7 8 ParameterExpression paramo = Expression.Parameter(typeof(MyObject), "param"); 9 ParameterExpression parami = Expression.Parameter(typeof(Int32), "newvalue"); 10 11 MethodCallExpression MethodCallSetterOfProperty = Expression.Call(paramo, SetterMethodInfo, parami); 12 Expression SetPropertyValueExp = Expression.Lambda(MethodCallSetterOfProperty, paramo, parami); 13 Expression<Action<MyObject, Int32>> SetPropertyValueLambda = (Expression<Action<MyObject, Int32>>)SetPropertyValueExp; 14 obj.Prop = 0; 15 Func<MyObject, Int32> Getter = GetPropertyValueLambda.Compile(); 16 Action<MyObject, Int32> Setter = SetPropertyValueLambda.Compile(); 17 watch.Reset(); 18 watch.Start(); 19 for (Int32 I = 0; I < iterations; ++I) 20 { 21 Setter(obj, Getter(obj) + 1); 22 } 23 watch.Stop(); 24 Console.WriteLine("Reflection setter with expression getter {0} iterations {1} ms", 25 iterations, watch.ElapsedMilliseconds); 26
The code seems really complicated but it is simple once you knows the structure of an expression tree. We need to represent the expression obj.Prop = obj.Prop + 1, but if you try to convert this into an expression you see that the compiler generates the error “An expression tree may not contain an assignment operator”, but this is not a problem, because obj.Prop = something means calling the setter method of the property. Armed with this knowledge I create two distinct expression, one for the Get part and the other for the Set part. The good thing of having an ExpressionTree is that he has a method called Compile(), that creates a code block that represents the expression. In line 15 16 I use this functionality to create two delegate.
Now the fun part, suppose you does not known the type at compile time (in the code included with this post I created a type on different assembly) you can still apply this technique.
1 Type otherType = Type.GetType("Other.OtherMyObject, Other"); 2 PropertyInfo ISomePinfo = otherType.GetProperty("Prop", BindingFlags.Public | BindingFlags.Instance); 3 4 param = Expression.Parameter(typeof(Object), "param"); 5 Expression convertedParam = Expression.Convert(param, otherType); 6 GetPropertyValueExp = Expression.Lambda(Expression.Property(convertedParam, "Prop"), param); 7 Expression<Func<Object, Int32>> dynamicGetterExpression = (Expression<Func<Object, Int32>>)GetPropertyValueExp; 8 Func<Object, Int32> dynamicGetter = dynamicGetterExpression.Compile();
In line 1 I get the type through reflection, and in line 2 get the property Prop with reflection too. Now I begin to create the expression I need for the Getter. If I want to get a property from an object that I do not know at compile time, I need to create a function of type Func<Object, Int32>, a function that gets an object and return an Int32 value, since the property is Int32. In line 4 I create the parameter for the expression of type object, then I create a Convert expression in line 5 (it is a cast) then I create the lambda that access the property. Finally I use the Compile method to obtain a Func<Object, Int32>.
This expression is the same of this instruction ((OtherMyObject) obj).Prop but since I does not know the type at compile time Expression Tree is the only way to write such a function. The setter part is similar, you can check on the source code. The fun part is that now I can write this code.
Object otherObj = Activator.CreateInstance(otherType); for (Int32 I = 0; I < iterations; ++I) { Int32 actualValue = dynamicGetter(otherObj); dynamicSetter(otherObj, actualValue + 1); }
The instance is created with Activator.CreateInstance because I really does not know the type at compile time, but I can use dynamicGetter and dynamicSetter with no problem. Here is the output of the timing.
Direct invocation 100000 iterations 1 ms Reflection invocation 100000 iterations 616 ms Expression Tree getter 100000 iterations 1 ms Expression tree with unknown object getter 100000 iterations 2 ms
You can see that the using this technique permits to completely bypass performance penalties that you have with reflection.
Source code can be found here.
alk.
Tags: Expression Tree .NET Framework






October 6th, 2008 at 2:33 pm
Use more advanced Lightweight Code Generation (LCG) instead of regular reflection, results should be pretty much the same (actualy that is what dynamicGetterExpression.Compile() uses). Of course expression trees are easier to code.
October 7th, 2008 at 3:24 am
I worked a lot with LCG, but expression tree are easier to use, you do not need to know IL, and the caller can obtain a simple Func
alk.
October 8th, 2008 at 6:41 am
I agree with MM, for instance check this out: http://jachman.wordpress.com/2.....hod-calls/
Actually this should be easier, because you actually don’t have to “write” the IL. Instead you write the C# code, compile it, and then you simply translate what ILDASM lists as the output.
October 8th, 2008 at 7:49 am
Yes, I’m sure that with LCG the code will be faster than regular expression, since the Compile method traverse the Expression Tree and generates the IL code, while with LCG you directly generate the IL without the intermediate ExpressionTree. As I said U just wanted to show an alternative approach to dynamic code generation with the use of ExpressionTree
.
October 14th, 2008 at 3:25 pm
Занимаюсь дизайном и хочу попросить автора http://www.nablasoft.com отправить шаьлончик на мой мыил) Готов заплатить…
February 24th, 2009 at 12:25 am
But the compile method for expression costs quite a lot
February 25th, 2009 at 1:53 am
Yes, but the cost for compiling the method is paid only the first time, as for most of techniques it is a trade off, if you does not matter waiting the first time it can be useful. Code generation at runtime is always slow during compilation.