InfiniTec - Henning Krauses Blog

Don't adjust your mind - it's reality that is malfunctioning

fun with .NET 4 expressions – Light speed edition

A few days ago I posted an article about the new .NET Expression features in .NET 4.0 (Fun with .NET 4 expressions). A few people commented and wrote the this was a pretty expensive way to synchronize data. Of course it was – performance wasn’t a design consideration. I merely followed the two rules of optimization:

  1. Don’t do it.
  2. (For experts only!) Don’t do it now.

And since the synchronization process was fast enough, I didn’t care.

However, just for the fun of it, I did some performance optimization and it is pretty amazing. The thing which made the original code rather slow was the fact that the same expressions were compiled over and over again. So an obvious improvement was to cache the compiled expressions and reuse them. So I introduced two dictionaries to hold the compiled expressions:

private static readonly Dictionary<Type, object> _SetterCache = new Dictionary<Type, object>();
private static readonly Dictionary<Type, object> _GetterCache = new Dictionary<Type, object>();

You may wonder why the type of the dictionary is Dictionary<Type, object>. The reason for this is that there is no other common base class for the type Func<TSource, TProperty>. The following this method checks the cache and compiles the expression if required:

private static Func<TTarget, TProperty> GetGetterMethod<TTarget, TProperty>(Expression<Func<TTarget, TProperty>> targetSelector)
    object getterObject;
    Func<TTarget, TProperty> getterMethod;
    var selectorType = targetSelector.Type;

    if (!_GetterCache.TryGetValue(selectorType, out getterObject))
        getterMethod = targetSelector.Compile();
        _GetterCache[selectorType] = getterMethod;
        getterMethod = (Func<TTarget, TProperty>) getterObject;
    return getterMethod;

I added a similar method to handle the update expression accordingly.

Finally, I hacked together a small test program which used the Stopwatch class to measure the synchronization speed. The result is quite impressing. Synchronizing an object with two properties 10,000 times yielded these results:

Elapsed for 10000 rounds (Slow): 00:00:08.0471936
Elapsed for 10000 rounds (Fast): 00:00:00.2009293

That is quite an improvement.

I’ve attached the source code to this post, so you can measure yourself.


Posted by Henning Krause on Sunday, December 5, 2010 9:00 PM, last modified on Sunday, December 5, 2010 8:38 PM
Permalink | Post RSSRSS comment feed

Comments (1) -

On 12/6/2010 3:08:59 PM Aaron United States wrote:


Very nice, thanks!

 +Pingbacks and trackbacks (1)