Skip to content

Instanciating a Type at Runtime – C# Benchmarks

Assuming you are familiar with C#;
If I give you a Type and tell you to create an object with it, you would automatically think of Activator.CreateInstance right?
What if I tell you that instanciating a Type using Expression Trees is much faster?

First of all, the code for the benchmarks is here:
https://github.com/zHaytam/InstanciateBenchmarks

Background

I am currently in an internship and the project I’m working on needs to be as extensible as possible.
Meaning that users/developers should have the possiblity to add new functionalities (or at least a variant of a functionality) easily.

For instance, I have a Manager class and a couple of default classes that inherit implement, each of them does something specific.
Now the idea is to make it possible for people to plug-in their SomethingManager class.

I ended up with a list of Type that inherit from Manager.
Now all I have to do is instanciate and execute these types when I need them.
Like most C# programmers, I immediately thought of Activator.CreateInstance!

However, there must be a faster way for instanciating a type right?

Instaciating a type – some of the ways

Let’s imagine that our base class is TestClass.

Activator:

ConstructorInfo (Reflection)

Expression Trees

Func<object> (Expression Trees)

Func<TestClass> (Expression Trees)

Results

InstanciateBenchmarks.Benchmarks-barplot
InstanciateBenchmarks.Benchmarks-barplot

I added the new TestClass() benchmark as a baseline.
As you can see, Expression Trees compiled
Func<object> or Func<TestClass> are so close to being as fast as the baseline.

On the other hand, Expression Trees compiled to a plain Delegate and called using DynamicInvoke() are extremely slow.
This is due to the fact that a
Delegate is dynamically invoked, .net has to use Reflection to figure out the Type and other informations, and this happens everytime.

For more informations, check this Stackoverflow question.

Raw results

MethodJobMeanErrorStdDevRatioRatioSDRank
NewClr3.722 ns0.0581 ns0.0544 ns1.000.002
ActivatorClr48.439 ns0.1852 ns0.1733 ns13.020.209
ConstructorClr137.333 ns0.3617 ns0.3383 ns36.910.5411
DelegateClr727.431 ns1.6431 ns1.2829 ns195.503.1517
FuncClr11.439 ns0.0742 ns0.0658 ns3.070.047
TypedFuncClr10.749 ns0.0752 ns0.0703 ns2.890.046
NewCore3.973 ns0.0417 ns0.0370 ns1.070.023
ActivatorCore43.673 ns0.1425 ns0.1333 ns11.740.168
ConstructorCore96.602 ns0.3215 ns0.3007 ns25.960.3910
DelegateCore524.034 ns1.1478 ns1.0736 ns140.842.1016
FuncCore6.282 ns0.2092 ns0.3195 ns1.720.095
TypedFuncCore4.538 ns0.0891 ns0.0833 ns1.220.024
NewCoreRT3.187 ns0.0759 ns0.0710 ns0.860.021
ActivatorCoreRT328.310 ns1.3142 ns1.2293 ns88.231.2415
ConstructorCoreRT142.282 ns0.7171 ns0.6708 ns38.240.5512
DelegateCoreRT298.431 ns2.0301 ns1.8990 ns80.211.3614
FuncCoreRT220.747 ns0.5149 ns0.4816 ns59.330.8413
TypedFuncCoreRT219.806 ns1.5278 ns1.4291 ns59.081.0213

To sum up, instanciating a type at runtime can be done in multiple ways.
The fasted way (in these benchmarks) is using Expression Trees to generate a typed
Func<X>` and invoke it when needed.

For the future, I should also benchmark running IL Code directly.

Published inC#Programming

Leave a Reply

avatar
  Subscribe  
Notify of