A Super-Fast C# Extension Method using Expression Trees to Create an instance from a Type

Having written an extension method to create an instance from a Type and been a bit underwhelmed by its performance, I looked into exactly what was happening and have now got it working much, much faster.

To recap, the problem with the first version of this method is that it cached the Funcs it created with all their argument types as object, which meant they had to be cast every time the Func was invoked. This can be seen in all the Convert calls in Visual Studio's expression visualiser:

Expression Visualiser

It turned out that this way of doing things was 10 times slower than using Activator.CreateInstance() with no constructor parameters, and took 70% of the time when one or more parameters was used. I was sure I could improve on that :)

With the source of the performance problem being the type of the cache forcing casting of the arguments, what I needed was a type-safe cache. The types in question are the types of the constructor parameters used when Type.GetInstance() is called, so what I needed was some sort of dynamic cache which would retain those types. I read C# in Depth recently, and picked up a handy bit of trivia to do with static, generic types.

When you use a static generic type, the C# compiler creates a singleton instance of that type for each unique combination of type parameters you use. That means with a static, generic helper class, the compiler would create a type-safe cache for me, which I can key by the Type being constructed. So that was what I did:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
 
public static class TypeExtensions
{
    /// <summary>
    /// Returns an instance of the <paramref name="type"/> on which the method is invoked.
    /// </summary>
    /// <param name="type">The type on which the method was invoked.</param>
    /// <returns>An instance of the <paramref name="type"/>.</returns>
    public static object GetInstance(this Type type)
    {
        return GetInstance<TypeToIgnore>(type, null);
    }
 
    /// <summary>
    /// Returns an instance of the <paramref name="type"/> on which the method is invoked.
    /// </summary>
    /// <typeparam name="TArg">The type of the argument to pass to the constructor.</typeparam>
    /// <param name="type">The type on which the method was invoked.</param>
    /// <param name="argument">The argument to pass to the constructor.</param>
    /// <returns>An instance of the given <paramref name="type"/>.</returns>
    public static object GetInstance<TArg>(this Type type, TArg argument)
    {
        return GetInstance<TArg, TypeToIgnore>(type, argument, null);
    }
 
    /// <summary>
    /// Returns an instance of the <paramref name="type"/> on which the method is invoked.
    /// </summary>
    /// <typeparam name="TArg1">The type of the first argument to pass to the constructor.</typeparam>
    /// <typeparam name="TArg2">The type of the second argument to pass to the constructor.</typeparam>
    /// <param name="type">The type on which the method was invoked.</param>
    /// <param name="argument1">The first argument to pass to the constructor.</param>
    /// <param name="argument2">The second argument to pass to the constructor.</param>
    /// <returns>An instance of the given <paramref name="type"/>.</returns>
    public static object GetInstance<TArg1, TArg2>(this Type type, TArg1 argument1, TArg2 argument2)
    {
        return GetInstance<TArg1, TArg2, TypeToIgnore>(type, argument1, argument2, null);
    }
 
    /// <summary>
    /// Returns an instance of the <paramref name="type"/> on which the method is invoked.
    /// </summary>
    /// <typeparam name="TArg1">The type of the first argument to pass to the constructor.</typeparam>
    /// <typeparam name="TArg2">The type of the second argument to pass to the constructor.</typeparam>
    /// <typeparam name="TArg3">The type of the third argument to pass to the constructor.</typeparam>
    /// <param name="type">The type on which the method was invoked.</param>
    /// <param name="argument1">The first argument to pass to the constructor.</param>
    /// <param name="argument2">The second argument to pass to the constructor.</param>
    /// <param name="argument3">The third argument to pass to the constructor.</param>
    /// <returns>An instance of the given <paramref name="type"/>.</returns>
    public static object GetInstance<TArg1, TArg2, TArg3>(
        this Type type,
        TArg1 argument1,
        TArg2 argument2,
        TArg3 argument3)
    {
        return InstanceCreationFactory<TArg1, TArg2, TArg3>
.CreateInstanceOf(type, argument1, argument2, argument3);     }     // To allow for overloads with differing numbers of arguments, we flag arguments which should be      // ignored by using this Type:     private class TypeToIgnore     {     }     private static class InstanceCreationFactory<TArg1, TArg2, TArg3>     {         // This dictionary will hold a cache of object-creation functions, keyed by the Type to create:         private static readonly Dictionary<TypeFunc<TArg1, TArg2, TArg3, object>> _instanceCreationMethods =              new Dictionary<TypeFunc<TArg1, TArg2, TArg3, object>>();         public static object CreateInstanceOf(Type type, TArg1 arg1, TArg2 arg2, TArg3 arg3)         {             CacheInstanceCreationMethodIfRequired(type);             return _instanceCreationMethods[type].Invoke(arg1, arg2, arg3);         }         private static void CacheInstanceCreationMethodIfRequired(Type type)         {             // Bail out if we've already cached the instance creation method:             if (_instanceCreationMethods.ContainsKey(type))             {                 return;             }             var argumentTypes = new[] { typeof(TArg1), typeof(TArg2), typeof(TArg3) };             // Get a collection of the constructor argument Types we've been given; ignore any              // arguments which are of the 'ignore this' Type:             Type[] constructorArgumentTypes = argumentTypes.Where(t => t != typeof(TypeToIgnore)).ToArray();             // Get the Constructor which matches the given argument Types:             var constructor = type.GetConstructor(                 BindingFlags.Instance | BindingFlags.Public,                 null,                 CallingConventions.HasThis,                 constructorArgumentTypes,                 new ParameterModifier[0]);             // Get a set of Expressions representing the parameters which will be passed to the Func:             var lamdaParameterExpressions = new[]             {                 Expression.Parameter(typeof(TArg1), "param1"),                 Expression.Parameter(typeof(TArg2), "param2"),                 Expression.Parameter(typeof(TArg3), "param3")             };             // Get a set of Expressions representing the parameters which will be passed to the constructor:             var constructorParameterExpressions = lamdaParameterExpressions                 .Take(constructorArgumentTypes.Length)                 .ToArray();

// Get an Expression representing the constructor call, passing in the constructor parameters:             var constructorCallExpression = Expression.New(constructor, constructorParameterExpressions);             // Compile the Expression into a Func which takes three arguments and returns the constructed object:             var constructorCallingLambda = Expression                 .Lambda<Func<TArg1, TArg2, TArg3, object>>(constructorCallExpression, lamdaParameterExpressions)                 .Compile();             _instanceCreationMethods[type] = constructorCallingLambda;         }     } }

The Funcs created by this version of the method now look like this in the Expression Visualiser:

ExpressionVisualiser_2

That's more like it - no casting! So how does it perform compared to the previous set of methods? Well, here's the output of the same performance measurement I ran before; the third column shows the total number of ticks taken to create 100,000 objects, the fourth the number of ticks taken per object:

GetInstancePerformance_2

To sum up the improvement:

  • An instance is now created in 5 ticks - between 10% and 7% of the time taken by Activator.CreateInstance()
  • Because the arguments aren't cast, performance doesn't degrade when constuctors are used with extra parameters

That's more like it! I was especially pleased to be able to apply a bit of trivia I read from a C# book to a problem like this and see a genuine improvement. The more I use and get used to Expression Trees, the more I like them and find uses for them :)

Print | posted @ Sunday, February 19, 2012 7:42 PM

Comments on this entry:

Gravatar # re: A Super-Fast C# Extension Method using Expression Trees to Create an instance from a Type
by Nadav at 2/20/2012 2:40 PM

Instead of GetConstructorParameterExpressions()
can't you just use lamdaParameterExpressions.Take(constructorArgumentTypes.Lenth).ToArray()?
Gravatar # re: A Super-Fast C# Extension Method using Expression Trees to Create an instance from a Type
by Nadav at 2/20/2012 2:51 PM

Btw, Your caching is not thread safe...
Gravatar # re: A Super-Fast C# Extension Method using Expression Trees to Create an instance from a Type
by Steve Wilkes at 2/20/2012 9:18 PM

Hi Nadav,

Thanks very much for the feedback - both good spots! - I've now updated the code. As a lock statement would have to cover the entire Cache method I've attended to thread safety by using the dictionary's indexed setter instead of .Add(); it's possible two threads could overlap inside the method, but they'd both add the same thing to the dictionary, so I *think* it's ok. Thanks again! :)
Gravatar # re: A Super-Fast C# Extension Method using Expression Trees to Create an instance from a Type
by Hilário Cunha at 2/21/2012 9:09 AM

For the parameterless constructor you can use the following code.

static T GetInstance<T>() where T : new()
{
return new T();
}

It's much faster.
Gravatar # re: A Super-Fast C# Extension Method using Expression Trees to Create an instance from a Type
by Steve Wilkes at 2/21/2012 9:10 AM

Hi Hilario,

These methods are for use when you don't have the Type at design time, and so can't use a generic method like GetInstance<T>().
Gravatar # re: A Super-Fast C# Extension Method using Expression Trees to Create an instance from a Type
by Hilário Cunha at 2/21/2012 9:10 AM

If the type is not known at design time probably the best option is to call Activator.CreateInstance for the parameterless constructor. If i'm not wrong the BCL team have that case optimized.
Gravatar # re: A Super-Fast C# Extension Method using Expression Trees to Create an instance from a Type
by Steve Wilkes at 2/21/2012 9:11 AM

Yeah, that's a fair point - the performance test results do show Activator.CreateInstance() as faster in the parameterless case, and I did use it for the parameterless overload in my first attempt at these methods. Then again it's the difference between 2 and 5 ticks, so I think personal taste between absolute speed and consistency plays a part in the decision, too.
Gravatar # re: A Super-Fast C# Extension Method using Expression Trees to Create an instance from a Type
by Nadav at 2/21/2012 9:43 AM

Hi Steve,

I've been playing around with the code trying different things and here are my conclusions:

1. The caching in the dictionary takes a big chunk of the time, you can get a 40% speed improvement if instead of using Contains()&Get_Item you use TryGetValue().

2. If you use a ConcurrentDictionary instead of a dictionary (TryGetValue & adding using TryAdd ) you still get a better performance than your code.
The strange thing is that GetOrAdd() seems to be slower than (TryGetValue+TryAdd). For one of by test classes it was 20% slower, for the other it was 28 TIMES slower!!!

For what it's worth, I don't think the bad performance of Activator.CreateInstance is because of the casting. The cost of the casting is insignificant relative to the time it take to execute the CreateInstance function.
I think the problem is that the CreateInstance gets it's parameters as object[] and then need to get the types of the parameters out of them. The Activator code probably also uses shared code that is used by the other overrides of CreateInstance so it's probably much more complicated...
Gravatar # re: A Super-Fast C# Extension Method using Expression Trees to Create an instance from a Type
by Nadav at 2/21/2012 10:30 AM

BTW, what ticks are you using for measurement? StopWatch.ElapsedTicks?
If so, then what computer are you running these tests on? My results are 2 orders of magnitude slower than yours...

Gravatar # re: A Super-Fast C# Extension Method using Expression Trees to Create an instance from a Type
by Steve Wilkes at 2/21/2012 12:31 PM

Hi Nadav,

Interesting findings! I'll have a play around with that myself soon. Thanks!

The casting I've referred to is from my first attempt at these methods rather than Activator.CreateInstance() - I've never seen the inside of that.

For the Ticks measurement I subtracted a start DateTime from an end DateTime; I'm vaguely aware that's not the same thing as StopWatch, but I was only interested in relative speeds.
Gravatar # re: A Super-Fast C# Extension Method using Expression Trees to Create an instance from a Type
by Andy at 2/13/2015 1:19 PM

How would you get an instance of an object with the above code by using the string name of the object instead of passing in the Type
Gravatar # re: A Super-Fast C# Extension Method using Expression Trees to Create an instance from a Type
by Steve Wilkes at 2/14/2015 10:57 AM

Hi Andy,

You'd have to convert from the name of the Type to a Type object and then call the Type overload - as coincidence would have it the very first (and second) blog(s) I posted were on finding Type objects based on filters, so you could call:

var type = Assembly
.GetExecutingAssembly()
.GetAvailableTypes(
typeFilter: t => (t.Name == "MyTypeName"))
.First();

var instance = type.GetInstance();

The blog with the Type-finding code is here: http://wblo.gs/bab
Gravatar # re: A Super-Fast C# Extension Method using Expression Trees to Create an instance from a Type
by Thread-Safety at 9/19/2016 12:09 PM

To ensure thread-safety, you can also use `ConcurrentDictionary<Type, Func<TArg, TArg2, object>>`

Kind regards
Post A Comment
Title:
Name:
Email:
Comment:
Verification: