Search code examples
c#genericsreflectionactivatortype-constraints

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


If I have a type parameter constraint new():

void Foo<T>() where T : new()
{
    var t = new T();
}

Is it true that new T() will internally use the Activator.CreateInstance method (i.e. reflection)?


Solution

  • 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.