Introduction

There are a number ways to dynamically instantiate objects at runtime. There are some methods built-in to the .NET Framework, such as the System.Activator class, Reflection, and ways you can brew your own. Each with its own consequences and payoff's. During my search for the fastest way to dynamically instantiate objects, I consolidated information about the various methods, their practicality, and respective performance. Please note that this article applies to .NET 1.1 - my knowledge of 2.0 is still limited as my primary work environment is (more like "is struggling to be") a .NET 1.1 shop. In the more current versions of .NET, there are additional ways to achieve what I present in this article.

This article assumes an understanding of Reflection and a bit about MSIL. I'm not an MSIL guru in any form, so I won't spend much time on the subject. I had to experiment quite a bit, but luckily, there are some great tools to make experimenting easier. See the References section for details.

Background

The contents of this article are not new. These performance benchmarks have been performed many times. The References section lists articles that I've read and used to compile this article. My intent is to provide a comparison based on my understanding, as well as to demonstrate how a factory can be created to make the creation of dynamic objects as fast as possible. I look forward to comments and suggestions.

Common Methods of Creating Dynamic Objects

The fastest way to instantiate an object is by directly calling its constructor.

Dim MyWidget AsNew SuperWidget

This, however, does not allow us to write generic, type-independent code. There are often times that a Type is not know until runtime, so let's examine the following methods of dynamic object creation and their respective performance. The screenshot above shows my benchmark results. If you're already familiar with the following, you may want to skip ahead to the Dynamic Factory section.

The System.Activator Class:

Though, 'easy' comes at a price; it's by far the worst performing. In certain cases, performance may not be a big concern. If you only need to create a few objects here and there, then it's most likely OK. However, if you have a need to frequently create many dynamic objects, the System.Activator is not a good choice.

System.Reflection - GetConstructor:

Another simple method is to use Reflection. The following shows how to instantiate an object by obtaining its ConstructorInfo:

Invoking the constructor, if cached, out-performs the System.Activator. So, to avoid calling GetConstructor each time we need a new instance, a Hashtable is used for caching the Type and, in this case, the ContructorInfo. While insignificant, the Hashtable lookups will incur a small performance hit.

System.Reflection - GetMethod + Delegate:

Yet another method is to create and cache a Delegate. Without a Hashtable/Cache lookup, this method is just about as fast as direct instantiation, but has some serious problems. The following shows how it's done:

Because it's Shared, you cannot enforce its existence with an Interface or base class. You just have to assume it's there and spelled correctly. Not a practical approach if you are creating an API or application for distribution. But, there is a solution...

(Addendum) I stumbled across the FormatterServices class while digging through Microsoft's ObjectBuilder DI Framework. I was curious as to what methods were being used to instantiate objects. Upon investigation, I found that when an object is de-serialized, an uninitialized instance of it is created by the deserializer. In other words, it's instantiated without calling any of its constructors. Neat! Subsequently, the object's members are repopulated with the previously serialized values.

In the previous example, a Shared method within each Widget returned an instance of the respective type. Now, we can essentially achieve the same or better performance without an unenforceable Shared method. This allows the GetWidgetInstance() method to be enforced by an Interface or MustOverride in the base class. Here's how it's done:

Override it as required, and return an instance. If other initialization parameters are required, they can be added to the GetInstance() method in the base class, i.e., Public MustOverride Function GetInstance(host as Object) As Widget.

Each Widget becomes its own factory. Not entirely dynamic, as you still need to hard code the type being returned. Though, the nice thing here is that you can easily run additional code, call methods, and set properties before returning the Widget. The following WidgetFactory, a Widget itself, is just an instance of a specific Widget type. However, no constructor calls were made, so any initialization code was never executed. Because of this, it's possible that calls to other members will result in an exception. But that's okay for our purposes. A generic factory class can conceal the details to prevent this from happening as well as cache each uninitialized Widget. To pump out instances, you simply...

System.Reflection.Emit - The Runtime Dynamic Factory:

To achieve the same performance as the Delegate method and still enforce our members by way of a base class or Interface, we can use the Reflection.Emit namespace to generate runtime "machine" assemblies for each Widget. Each machine returns only a single type of Widget. A WidgetFactory is responsible for creating the machines and returning Widgets from them. Each machine is cached in a Hashtable, keyed by the Type of Widget it creates. To achieve maximum performance, the assembly (or AppDomain) is pre-scanned for Widgets at startup. Because the machines are pre-built, an extra Hashtable lookup to check for their existence on every call is avoided. To build a WidgetInstanceMachine, we first need to define an Interface.

Because of my limited knowledge of MSIL, I used Reflector in addition to a bit of trial and error to get the desired results. If we save and open one of the machine assemblies, we'll see the following...

Another helpful tool is DILE. You can see the two OpCodes that were emitted by the ILGenerator. Creating/hard-coding a single machine, then compiling and reviewing the IL shows the OpCodes you need to emit to reproduce the machine at runtime.

And finally, when all the machines are running, the WidgetFactory can retrieve a machine and get a Widget from it.

Points of Interest

The IWidgetInstanceMachine is a very simple implementation. With a little extra effort, you can pass parameters through the machine's GetInstance(param1, ...) method to be used when a Widget is created. This allows you to create more complex machines that behave more like factories themselves.

References & Credits

A somewhat dated, but ever still excellent discussion on the topic can be found at Performance of Dynamic Object Instantiation. I also used pieces of the performance benchmarking code, and was enlightened by the Delegate approach.