Posted in reflection, c#

Newing up T

Parameterless constructor

new()

By far the most readable way to new up T.

As long as your type has a parameterless constructor - you're good to go. It's also worth noting that this is just syntactic sugar - it's still very much reflection.
You can implement this method very simply.

public class Foo<T> where T : new() 
{
    public T BuildT()
    {
        return new T();
    }
}

As you added the new() constrained to the class declaration, the compiler knows that T should have a parameterless constructor.

Activator.CreateInstance()

var obj = Activator.CreateInstance<T>();

Less code, this does exactly the same job as new(). In fact, the CLR emits a call to Activator.CreateInstance() when you use new(). So in terms of performance there is nothing between them.

Cached compiled lambda

In come the big guns.

If we ever need to instantiate a large volume of objects - that's where a compiled lambda performs better. Of course you will need to cache the resulting delegate so that you don't have to compile the expression every time you want to build an object of type T.

IDictionary<Type, Func<T>> cache = new Dictionary<Type, Func<T>>();

public object BuildObject()
{
    Func<T> cachedFunc;
    if (cache.TryGetValue(typeof(T), out cachedFunc))
    {
        return cachedFunc();
    }
    Func<T> func = Expression.Lambda<Func<T>>(Expression.New(typeof(T))).Compile();
    cache.Add(typeof(T), func);

    return func();
}

It's pretty ugly code. And 99% of the time you won't need to put such a solution into production.

Let's see some benchmarks

There are two measurements which I chose to benchmark.

  1. Method vs method (new() vs Activator etc...)
  2. .NET 3.5 vs .NET 4.5

Method vs method

Each reflection method was used to create 100 million objects. The test was ran several times and an average was calculated. The results in the graph are shown in milliseconds. So naturally - lower is better.

Parameter less benchmark

As you can see there is nothing in it between new() and Activator.CreateInstance(). They are one in the same when it comes down to performance.
However the cached lambda comes in 16.4% faster. Remembering that this is over 100 million objects

However

If we run the same methods, but over 10 thousand objects - the results are completely different:

  • new() - 2ms
  • Activator.CreateInstance() - 1ms
  • Cached Lambda - 70ms

.NET 3.5 vs .NET 4.5

This is an interesting test. Exactly how much faster is reflection in .NET 4.5 than in .NET 3.5. I will compare the results from running our benchmarks in the .NET 4.5 and .NET 3.5 frameworks.

Parameterless .NET 100 million

Parameterless .NET 10 million

Parameterless .NET 10 million

We can clearly see that reflection has been given a lot of love in .NET 4.5.
According to our results - Activator is a massive 80% faster running in .NET 4.5! Our cached lambda is coming in 33% slower (analysing this would be digressing too much, maybe another time!).


Constructor with a parameter

There are two methods to test for creating an object with reflection which take a parameter (there is IL too but that is not part of this article).

We will be focusing on Activator.CreateInstance() and cached lambda again. Only this time we will be passing in a parameter.

Activator

Again the code is still very simple using the Activator class. This is its biggest advantage over any other method to create an object with a parameter using reflection.

var obj = Activator.CreateInstance(typeof(T), arg);

Cached lambda

Very similar to the parameterless version. Only first, we need to reflect over the type, and get the correct ConstructorInfo. We also need to get a ParameterInfo object for our parameter. Together, these will build our expression.

IDictionary<Type, Func<int, T>> cache = new Dictionary<Type, Func<int, T>>();

public object BuildObject(int arg)
{
    Func<int, T> cachedFunc;
    if (cache.TryGetValue(typeof(T), out cachedFunc))
    {
        return cachedFunc(arg);
    }

    var constructor = typeof(T).GetConstructor(new[] { typeof(int) });
    var paramExpression = Expression.Parameter(typeof(int), "arg");

    Func<int, T> func = Expression.Lambda<Func<int, T>>(Expression.New(constructor, paramExpression), paramExpression).Compile();
    cache.Add(typeof(T), func);

    return func(arg);
}

Much more code, which means more to maintain. My cache is pretty incoherent (made for this benchmark only), improvements could be made in many places with this method, but it is good enough to serve our tests.

Benchmark

Method vs method

Running under the conditions as the parameterless benchmarks. I ran each method several times, creating 100 million objects.

Benchmark with parameter

Here you can see Activator taking 126 seconds to create 100 million objects. Where it only takes the lambda 10-11 seconds.

As you would expect, the fewer objects we create, the more the lambda's advantage diminishes. Given we create 10 thousand objects:

  • Activator - 14ms
  • Cached lambda - 71ms

The tipping point is around 60 thousand objects. When the lambda outperforms than the Activator method.

.NET 3.5 vs .NET 4.5

Same test as before. Only this time I have missed out on the 100 million instances test. This would of just been too slow, and I'm too impatient to wait around for it; but here are the others.

With a parameter .NET 10 million

With parameter .NET 10 thousand

The gap isn't as large as the parameterless tests, but still; it stands to prove the performance increase between .NET 3.5 and 4.5.


Wrap up

In most cases it's not going to be worth the optimisation. Keeping readability and maintainability in your application should ultimately dictate which method you choose.

That being said, if you are building objects which do not require any arguments - there is very little in it. You will be gaining 2-3 seconds when creating 100 million objects.

On the flip side, if your objects do require arguments, and your process is creating more than 60 thousand objects; consider the lambda.

Of course these are very generic benchmarks. In the real world, results could differ massively.

You can also use IL to create objects, which I believe to be faster than all the methods I have listed. However adding IL code to a production application is unspeakable!