Daniel Palme

Daniel Palme

.NET consultant from Germany.

Blog > Reflection vs. compiled expressions vs. delegates - Performance comparision

Reflection vs. compiled expressions vs. delegates - Performance comparision

I'm currently working on an application which uses reflection to create a generic UI. Therefore I was interested in the performance impact of reflection. In this post I will do a comparison between the various possibilities to access a property.

The test setup

The following methods are used to access a property called Name in a class Person:

Access the property directly:

string name = p.Name;

Use reflection:

var property = p.GetType().GetProperty("Name");
string name = (string)property.GetValue(p, null);

This test is executed twice. First the PropertyInfo is created in every iteration. In the second test one instance is reused.

Use compiled expression:

ParameterExpression arg = Expression.Parameter(p.GetType(), "x");
Expression expr = Expression.Property(arg, "Name");

var propertyResolver = Expression.Lambda<Func<Person, object>>(expr, arg).Compile();

string name = (string)propertyResolver(p);

This test is also executed twice. First the Expression is created in every iteration. In the second test one instance is reused.

Use delegates:

ParameterExpression arg = Expression.Parameter(p.GetType(), "x");
Expression expr = Expression.Property(arg, "Name");

var propertyResolver = Expression.Lambda(expr, arg).Compile();

string name = (string)propertyResolver(p);

This seems to be the same as the test with the compiled expression. But there is a subtle change: The lambda is created without type information.

Each test is executed 1.000.000 times and the overall time is measured.

The results

Overview

TestDuration [ms]
Regualar property31
Reflection1026
Reflection with cached PropertyInfo510
Compiled Expression286.879
Cached compiled Expression58
Delegate299.173
Cached delegate3008

Conclusion

Using the property is of course the fasted way to get the value of a (known) property. But also reflection is not that slow, especially when you reuse the PropertyInfo object.
Compiling an expression is a time consuming operation, but if you reuse the compiled expression the performance is equal to the regular property access. Compilation of expressions only makes sense, if you have to process a lot of objects.
Delegates are relatively slow, because type information is missing compared to compiled expressions.

Downloads

ReflectionPerformance.7z


Subscribe to RSS Feed

Tags: .NET, C#
 

Related posts

 

New comment

:

:

:

:

 

Comments

#1
Miguel Angelo

Miguel Angelo

05/23/2013

The cached delegate time of 3008ms makes no sense... it should be faster than the no-cache version of itself, that took 299.173ms... shouldn't it?
 
#2
Daniel

Daniel

05/24/2013

@Miguel:
It is faster. I think you are misinterpreting the numbers. The '.' is not used as a decimal separator but as a grouping symbol.
 
#3
Sebastiaan Dammann

Sebastiaan Dammann

06/07/2013 | http://damsteen.nl/

For some reason the tests yields different results here. The "Cached delegate" is actually quite a bit faster than "Cached compiled Expression". The cached delegate takes around 50 ms.
 
#4
Kim

Kim

09/24/2013

Thanks for this!

If anyone is interested, here's the code for the compiled setter (my apologies if the formatting gets messed up):

ParameterExpression arg = Expression.Parameter(typeof (Person));
Expression expr = Expression.Property(arg, propertyName);
Expression<Func<Person, string>> get = Expression.Lambda<Func<Person, string>>(expr, arg);
Getter = get.Compile();


var member = get.Body;
var param = Expression.Parameter(typeof (string), "value");
Setter =
Expression.Lambda<Action<Person, string>>(Expression.Assign(member, param), get.Parameters[0], param)
.Compile();
 
#5
Yves

Yves

02/12/2014 | http://dev.unclassified.de/

Thank you very much for this brilliant piece of code, both the getter and the setter for compiled expressions. I've been able to build a simple custom O/RM with model attributes around this in a day (~1000 loc) and by measurements with reading 45000 records it takes around 1.5 the time of assigning directly from DbDataReader to model properties. With much less code to write and to maintain!
 
#6
co-logic

co-logic

04/24/2014

Hey,
thanks for this code, helped me alot.

What about this line? I use it for my O/R, where I need fast execution, but yet a generic (object) accessor in the base class. It took about 60ms on my machine:

// Dictionary for the base class. No type information needed!
var d = new Dictionary<string, Func<object, object>>(StringComparer.OrdinalIgnoreCase);

// Filling the dictionary in the derived class
d.Add("Name", (per) => { return ((Person)per).Name; });

// Measuring (60ms!)
for (int i = 0; i < 1000000; i++)
{
sb.AppendLine(d["Name"](p).ToString());
}
 
#7
co-logic

co-logic

04/24/2014

The Setter for completeness:


// Base Schema Class (no types)
var setProperty = new Dictionary<string, Action<object, object>>(StringComparer.OrdinalIgnoreCase);


// Derived Class
setProperty.Add("Name", (n, v) => ((Person)n).Name = (string)v);

// Call
setProperty["Name"](p, Value);
 
#8
Stanislav

Stanislav

07/23/2014 | http://yarmonov.pro

I'm afraid delegate performance is wrong. You measured dynamic invocation, not delegate. Delegate itself is a signature, so it contains all required type information. BTW delegate is generic param for expression compilation. The more proper benchmark will be:

public delegate string DelegateSignature(Person person);

public static string DelegateImplementation(Person person)
{
return person.Name;
}

private static void CachedDelegate(Person p)
{
DelegateSignature d = Program.DelegateImplementation;

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000000; i++)
{
sb.AppendLine(d(p).ToString());
}
}