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

前端 未结 2 1988
暗喜
暗喜 2020-12-10 13:00

If I have a type parameter constraint new():

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

Is it true that

相关标签:
2条回答
  • 2020-12-10 13:19

    Yes. It does for reference types.

    Using ILSpy on the following release-compiled code:

        public static void DoWork<T>() where T: new()
        {
            T t = new T();
            Console.WriteLine(t.ToString());
        }
    

    Yielded

    .method public hidebysig 
        instance void DoWork<.ctor T> () cil managed 
    {
        // Method begins at RVA 0x2064
        // Code size 52 (0x34)
        .maxstack 2
        .locals init (
            [0] !!T t,
            [1] !!T CS$0$0000,
            [2] !!T CS$0$0001
        )
    
        IL_0000: ldloca.s CS$0$0000
        IL_0002: initobj !!T
        IL_0008: ldloc.1
        IL_0009: box !!T
        IL_000e: brfalse.s IL_001b
    
        IL_0010: ldloca.s CS$0$0001
        IL_0012: initobj !!T
        IL_0018: ldloc.2
        IL_0019: br.s IL_0020
    
        IL_001b: call !!0 [mscorlib]System.Activator::CreateInstance<!!T>()
    
        IL_0020: stloc.0
        IL_0021: ldloca.s t
        IL_0023: constrained. !!T
        IL_0029: callvirt instance string [mscorlib]System.Object::ToString()
        IL_002e: call void [mscorlib]System.Console::WriteLine(string)
        IL_0033: ret
    } // end of method Program::DoWork
    

    Or in C#:

    public void DoWork<T>() where T : new()
    {
        T t = (default(T) == null) ? Activator.CreateInstance<T>() : default(T);
        Console.WriteLine(t.ToString());
    }
    

    JIT will create different compiled instructions for each different value type parameter passed in, but will use the same instructions for reference types -- hence the Activator.CreateInstance()

    0 讨论(0)
  • 2020-12-10 13:21

    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.

    0 讨论(0)
提交回复
热议问题