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.
- Method vs method (new() vs Activator etc...)
- .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.
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.
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.
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.
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!