开发者

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

开发者 https://www.devze.com 2023-03-20 09:10 出处:网络
If I have a type parameter constraint new(): void Foo<T>() where T : new() { var开发者_高级运维 t = new T();

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)?


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.


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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号