Reflection is a powerful feature of the .NET platform. Whether it’s for querying a type’s properties or creating instances of objects dynamically, reflection can help in many architectural designs. But as Uncle Ben said:
With great power comes great responsibility
In fact, as a programmer you have to be careful when you use reflection because it comes with a cost. In most cases, that cost is minimal and will not impact the performance or scalability of your application. But in some cases, that cost can truly bring your application to its knees. In this article I’ll analyze the performance of the Activator class and provide optimized implementations for most of its methods.
It’s important to note that the performance of the Activator class has been improved in .NET 4 compared to .NET 3.5.
There are many flavors of optimized CreateInstance implementations out there but I find most of them not really intuitive to use. There are generally 2 approaches to this problem: Compiling lambda expressions or generating dynamic methods in IL. Both approaches require code generation at runtime and therefore cannot be used without a JIT compiler (mono under iOS for example). The IL approach executes slightly faster than compiled lambdas so that’s what I’ll be using.
As Jon Skeet points out in his blog, invocation through reflection is quite slow and delegates provide a faster way of invoking methods. So my strategy to improve the performance of CreateInstance is to create and cache a delegate to the constructor of a given type.
To optimize the statically typed version of CreateInstance, we will use a static generic class which will hold the delegate to the constructor. So instead of calling:
We will use:
Simple and intuitive. Here’s the implementation:
The magic happens in the extension method Type.GetConstructorDelegate<T> which we will cover later on. This statically typed Activator also works for constructors with parameters as long as you know the exact parameter types of the constructor signature you are targeting:
Which can be called like this:
You can create more versions of the Activator class depending on the number of arguments you want to support: Activator<T, TArg1, TArg2>, Activator<T, TArg1, TArg2, TArg3>, etc.
To optimize this method we will create an extension method to the Type class. So instead of calling:
We will use:
Not as intuitive but this way we won’t have a namespace clash with multiple Activator classes. Another way would be to name the static classes FastActivator, FastActivator<T>, etc. and keep all the methods in one place. I’ll leave that up to you. Here’s how this extension method is implemented:
We can also create signatures with statically typed arguments:
Which can be used like this:
A static method with its associated PrivateActivator class will need to be created to support more arguments. The implementation of the PrivateActivator is straightforward:
It’s important to note that the parameter types must match exactly the constructor signature as we are not dynamically figuring out inheritance.
Activator.CreateInstance(Type, params object args)
Unfortunately, I don’t have an optimized version of this method. If you look in reflector, it is madness. Optimizing it would be quite a challenge and I’ll leave that to someone else to figure out 😉
So now let’s have a look at the implementation of the Type.GetConstructorDelegate() extension method which is really the core of this implementation.
So this is pretty straightforward, we find the ConstructorInfo corresponding to the input arguments portion of the delegateType. We then create a dynamic method that matches the delegateType. With the IL generator we load the arguments (if any), call the constructor and return the object.
So we’ve covered a lot of ground in this article. We’ve optimized most of the CreateInstance methods, cached everything and made sure our implementation was thread-safe by relying on concurrent collections and generic static classes. But how does it perform you might ask? Here’s a chart showing a comparison assuming a warm cache: