2011-07-15 11 views
14

Jeśli mam typ parametru ograniczenie new():Biorąc pod uwagę "where T: new()", "new T()" używa wewnętrznie Activator.CreateInstance?

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

Czy to prawda, że ​​new T() będzie wewnętrznie użyć metody Activator.CreateInstance (czyli odbicie)?

+2

Czy to ma znaczenie? – Oded

+6

@Oded Jeśli próbujesz lepiej zrozumieć środowisko, w którym programujesz, to tak - to ma znaczenie! :-) – Justin

+1

@Kragen: ildasm, monodis – sehe

Odpowiedz

11

Tak, to prawda. Edytuj 2: Oto dobre wyjaśnienie, w jaki sposób i dlaczego.

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

do weryfikacji Skompilowałem następującą metodę:

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

I to jest generowane IL gdy skompilowany z kompilatora C# w .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 
} 

Edycja: Kompilator C# 4 tworzy nieco inny, ale podobny kod:

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

W przypadku typu wartości nie wykorzystać aktywator, ale po prostu zwraca wartość default(T), w przeciwnym razie wywołuje metodę Activator.CreateInstance.

+0

@Jason: 'initobj' jest zdefiniowane jako" Inicjalizuje każde pole typu wartości pod podanym adresem do zerowego odwołania lub 0 odpowiedniego typu pierwotnego ... W przeciwieństwie do Newobj, initobj nie wywołuje metody konstruktora. jest przeznaczony do inicjowania typów wartości, a newobj służy do alokowania i inicjowania obiektów. " Nic nie wskazuje na to, że wywołuje domyślny konstruktor typu referencyjnego.Zakładam, że jest to odpowiednik 'default (T)' – CodesInChaos

+0

@CodeInChaos: Usunąłem już swój komentarz. Popełniłem błąd. – jason

+1

Okay, więc najważniejsze pytanie brzmi: dlaczego. Dlaczego kompilator nie wysyła właśnie instrukcji 'newobj'? – jason

1

Tak. Ma zastosowanie dla typów referencyjnych.

Korzystanie ILSpy na poniższym uwalnianiu skompilowany kod:

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

przyniosły

.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 

albo w C#:

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

JIT będzie tworzyć różne skompilowane instrukcje dla każdej innej wartości typ parametru przekazany, ale użyje tych samych instrukcji dla typów referencji - on nce the Activator.CreateInstance()

+1

Dotyczy także "typów wartości" . 'Patrz strona 544/Rozdział 11 książki - Język programowania w C# - wydanie 3'. –

Powiązane problemy