Edit: As a result of these tests, I’ve written a better-performing set of extension methods.
I recently wrote an extension method
which uses an Expression Tree to create a Func
which creates an instance of an object from its type.
With that done I thought I’d check the performance difference between my method and
Activator.CreateInstance()
, which it was intended to replace.
I wrote a simple console application which tested using new
, Type.GetInstance()
and
Activator.CreateInstance()
by creating 100,000 instances of objects with zero to three constructor
parameters and calculating the average time of each construction. For Type.GetInstance()
and
Activator.CreateInstance()
I created a single instance of each object before running the test
so they could perform any caching outside of the actual performance measurement.
The results were as follows; the third column shows the total number of ticks taken to create 100,000 objects, the fourth the number of ticks taken per object:
A few things to note:
-
Unsurprisingly, using
new
is always and by far the fastest way to go. -
With a parameterless constructor, using
Activator.CreateInstance()
is almost as fast as usingnew
, and much, much faster than usingType.GetInstance()
. -
When your constructor takes one or more parameters,
Type.GetInstance()
takes about 70% the time ofActivator.CreateInstance()
.
I find myself wondering why Type.GetInstance()
isn’t faster than it is; after all, aren’t Func
s
created by Expression Trees supposed to nearly as fast as regular code? I’ve not looked into it in
any great detail, but I think its performance is weighed down by the generic nature of the method
and the way the Func
s are cached.
Because the Func
s are cached in a dictionary which returns a Func<object, object, object, object>
,
calling the Func
requires an Expression to cast each argument to its correct type, and this introduces
overhead. This is confirmed by looking at the Expression Debug View in Visual Studio, which displays
the created Lambda like this:
With these results, I’m going to update the parameterless overload of Type.GetInstance()
to delegate
to Activator.CreateInstance()
, and I wonder if I might be able to use a generic helper class
to cache a strongly-typed Func
and so avoid the casting… something to consider (I’ve now considered
it and written new methods).
I guess it’s always best to make decisions based on data :)
Comments
3 comments