Why Does the C# Compiler Emit Activator.Createinstance When Calling New in with a Generic Type with a New() Constraint

C# - Why does a class, new() constraint use Activator.CreateInstanceT()?

There is no such instruction in CIL (http://www.ecma-international.org/publications/standards/Ecma-335.htm).

Assuming we can add one, an another implementation of this could be that in the Type's VTable we make the default constructor be indexed at index 0, and then the JIT can assume this information and emit code that does a VTable lookup, pick index 0 and call the function located at address pointed by this entry 0 in the VTable.

As you can see this requires a change in CLR data structures, possibly each object's layout, and likely a different solution for value types (I'm ignoring that case, because you specifically say class and new().

Given where T : new(), does new T() use Activator.CreateInstance internally?

Yes, this is true. Edit 2: Here's a good explanation of the how and why.

http://www.simple-talk.com/community/blogs/simonc/archive/2010/11/17/95700.aspx

For verification I compiled the following method:

public static T Create<T>() where T: new() {
return new T();
}

And this is the generated IL when compiled with the C# compiler in .NET 3.5 SP1:

.method public hidebysig static !!T Create<.ctor T>() cil managed
{
.maxstack 2
.locals init (
[0] !!T local,
[1] !!T local2)
L_0000: ldloca.s local
L_0002: initobj !!T
L_0008: ldloc.0
L_0009: box !!T
L_000e: brfalse.s L_001a
L_0010: ldloca.s local2
L_0012: initobj !!T
L_0018: ldloc.1
L_0019: ret
L_001a: call !!0 [mscorlib]System.Activator::CreateInstance<!!T>()
L_001f: ret
}

Edit: The C# 4 compiler creates slightly different, but similar, code:

.method public hidebysig static !!T Create<.ctor T>() cil managed
{
.maxstack 2
.locals init (
[0] !!T CS$1$0000,
[1] !!T CS$0$0001)
L_0000: nop
L_0001: ldloca.s CS$0$0001
L_0003: initobj !!T
L_0009: ldloc.1
L_000a: box !!T
L_000f: brfalse.s L_001c
L_0011: ldloca.s CS$0$0001
L_0013: initobj !!T
L_0019: ldloc.1
L_001a: br.s L_0021
L_001c: call !!0 [mscorlib]System.Activator::CreateInstance<!!T>()
L_0021: stloc.0
L_0022: br.s L_0024
L_0024: ldloc.0
L_0025: ret
}

In the case of a value type it doesn't use the activator but just returns the default(T) value, otherwise it invokes the Activator.CreateInstance method.

Why is using a Func so much faster than using the new() constraint on a generic sequence creator

The new() constraint only ensures that the type passed in has a parameterless constructor. If you actually call new T() (or whatever your type argument's name is), it actually does this:

Activator.CreateInstance<T>();

Which, at its core, uses reflection.

Is a variant of this possible with C# Generics?

You can't call parameterized constructors on generic types. Your Func<> version is the best approach here.

Does System.Activator.CreateInstance(T) have performance issues big enough to discourage us from using it casually?

As always, the only correct way to answer a question about performance is to actually measure the code.

Here's a sample LINQPad program that tests:

  • Activator.CreateInstance
  • new T()
  • calling a delegate that calls new T()

As always, take the performance program with a grain of salt, there might be bugs here that skews the results.

The output (timing values are in milliseconds):

Test1 - Activator.CreateInstance<T>() 
12342

Test2 - new T()
1119

Test3 - Delegate
1530

Baseline
578

Note that the above timings are for 100.000.000 (100 million) constructions of the object. The overhead might not be a real problem for your program.

Cautionary conclusion would be that Activator.CreateInstance<T> is taking roughly 11 times as much time to do the same job as a new T() does, and a delegate takes roughly 1.5 times as much. Note that the constructor here does nothing, so I only tried to measure the overhead of the different methods.

Edit: I added a baseline call that does not construct the object, but does the rest of the things, and timed that as well. With that as a baseline, it looks like a delegate takes 75% more time than a simple new(), and the Activator.CreateInstance takes around 1100% more.

However, this is micro-optimization. If you really need to do this, and eek out the last ounce of performance of some time-critical code, I would either hand-code a delegate to use instead, or if that is not possible, ie. you need to provide the type at runtime, I would use Reflection.Emit to produce that delegate dynamically.

In any case, and here is my real answer:

If you have a performance problem, first measure to see where your bottleneck is. Yes, the above timings might indicate that Activator.CreateInstance has more overhead than a dynamically built delegate, but there might be much bigger fish to fry in your codebase before you get (or even have to get) to this level of optimization.

And just to make sure I actually answer your concrete question: No, I would not discourage use of Activator.CreateInstance. You should be aware that it uses reflection so that you know that if this tops your profiling lists of bottlenecks, then you might be able to do something about it, but the fact that it uses reflection does not mean it is the bottleneck.

The program:

void Main()
{
const int IterationCount = 100000000;

// warmup
Test1();
Test2();
Test3();
Test4();

// profile Activator.CreateInstance<T>()
Stopwatch sw = Stopwatch.StartNew();
for (int index = 0; index < IterationCount; index++)
Test1();
sw.Stop();
sw.ElapsedMilliseconds.Dump("Test1 - Activator.CreateInstance<T>()");

// profile new T()
sw.Restart();
for (int index = 0; index < IterationCount; index++)
Test2();
sw.Stop();
sw.ElapsedMilliseconds.Dump("Test2 - new T()");

// profile Delegate
sw.Restart();
for (int index = 0; index < IterationCount; index++)
Test3();
sw.Stop();
sw.ElapsedMilliseconds.Dump("Test3 - Delegate");

// profile Baseline
sw.Restart();
for (int index = 0; index < IterationCount; index++)
Test4();
sw.Stop();
sw.ElapsedMilliseconds.Dump("Baseline");
}

public void Test1()
{
var obj = Activator.CreateInstance<TestClass>();
GC.KeepAlive(obj);
}

public void Test2()
{
var obj = new TestClass();
GC.KeepAlive(obj);
}

static Func<TestClass> Create = delegate
{
return new TestClass();
};

public void Test3()
{
var obj = Create();
GC.KeepAlive(obj);
}

TestClass x = new TestClass();
public void Test4()
{
GC.KeepAlive(x);
}

public class TestClass
{
}

Create intance of any C# class by generic way

You only need a method:

private static T InstantiateInstance<T>() where T : new() => new T();


Related Topics



Leave a reply



Submit