Recently I had to task to create a dynamic object creation factory in C#. So I thought I test all the options I have to check what performs best.
I also wanted to check the performance implications these options have with the number of parameters in the constructor.
The Options
- new T() – Using the new/constructor method to
instantiate objects - Activator.CreateInstance(typeof(T)) – Using the Activator class to instantiate objects
- ConstructorInfo.Invoke() – Using the constructor info reflection class to instantiate objects
- Func<T>() – Using compiled lambda expressions to instantiate objects
The Test
I ran some tests to see calculate how each of the techniques mentioned above perform. The tests were the following.
- Instantiate a class with 0 constructor parameters.
- Instantiate a class with 1 constructor parameters.
- Instantiate a class with 2 constructor parameters.
- Instantiate a class with 3 constructor parameters.
- Instantiate a class with 4 constructor parameters.
- Instantiate a class with 5 constructor parameters.
A million (1,000,000) times.
The test Classes
public class A0 {
public A0() {}
}
public class A1 {
public A1(object a) {}
}
public class A2 {
public A2(object a, object b) {}
}
public class A3 {
public A3(object a, object b, object c) {}
}
public class A4 {
public A4(object a, object b, object c, object d) {}
}
public class A5 {
public A5(object a, object b, object c, object d, object e) {}
}
The tests
var a0c = typeof(A0).GetConstructor(new Type[] {});
var a1c = typeof(A1).GetConstructor(new Type[] {
typeof(object)
});
//...
ParameterExpression paramA = Expression.Parameter(typeof(object), "a");
ParameterExpression paramB = Expression.Parameter(typeof(object), "b");
//...
Func < A0 > a0l = Expression.Lambda < Func < A0 >> (Expression.New(a0c)).Compile();
Func < object, A1 > a1l = Expression.Lambda < Func < object, A1 >> (Expression.New(a1c, new [] {
paramA,
}), paramA).Compile();
//...
for (int i = 0; i < ITERATIONS; i++) {
new A0();
}
for (int i = 0; i < ITERATIONS; i++) {
new A1(new object());
}
//...
for (int i = 0; i < ITERATIONS; i++) {
Activator.CreateInstance(typeof(A0));
}
for (int i = 0; i < ITERATIONS; i++) {
Activator.CreateInstance(typeof(A1), new object());
}
//...
for (int i = 0; i < ITERATIONS; i++) {
a0c.Invoke(new object[] {});
}
for (int i = 0; i < ITERATIONS; i++) {
a1c.Invoke(new object[] {
new object()
});
}
//...
for (int i = 0; i < ITERATIONS; i++) {
a0l();
}
for (int i = 0; i < ITERATIONS; i++) {
a1l(new object());
}
//...
The Results
Parameters Elapsed MS Elapsed Ticks
***** Create With New *****
0 Parameters 16 59990
1 Parameters 33 119313
2 Parameters 39 143419
3 Parameters 55 201836
4 Parameters 40 146842
5 Parameters 50 183507
***** Create With Activator *****
0 Parameters 51 185691
1 Parameters 790 2850419
2 Parameters 872 3145864
3 Parameters 965 3480102
4 Parameters 1109 4000650
5 Parameters 1186 4277491
***** Create With Constructor Info *****
0 Parameters 122 440423
1 Parameters 192 693479
2 Parameters 254 917203
3 Parameters 311 1123222
4 Parameters 366 1322253
5 Parameters 426 1537764
***** Create With Compiled Lambda *****
0 Parameters 10 38864
1 Parameters 15 55366
2 Parameters 21 76782
3 Parameters 28 101073
4 Parameters 36 131948
5 Parameters 51 184227
Conclusion
There is a major performance hit on Activator.CreateInstance() and ConstructorInfo.Invoke(), as soon as constructors start accepting parameters.
You can get away with using Activator.CreateInstance if you are application is independent on the performance of the creation of dynamic objects.
However…
If you application heavily relies on the performance of the creation of dynamic objects, it is advisable to use Compiled lambda expression instead of anything else.
Creating objects using compiled lambda performs as BETTER!?!?!? than the new()/constructor.
Leave a Reply