2011-07-15 11 views

risposta

11

Sì, questo è vero. Modifica 2: Ecco una buona spiegazione del come e perché.

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

Per la verifica ho compilato il seguente metodo:

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

E questo è il IL generato quando si compila con il compilatore C# 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 
} 

Modifica: Il compilatore C# 4 crea un codice leggermente diverso, ma simile:

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

Nel caso di un tipo di valore non utilizza l'attivatore ma solo restituisce il valore default(T), altrimenti invoca il metodo Activator.CreateInstance.

+0

@Jason: 'initobj' è definito come" Inizializza ogni campo del tipo valore in un indirizzo specificato su un riferimento null o uno 0 del tipo primitivo appropriato ... A differenza di Newobj, initobj non chiama il metodo del costruttore. è inteso per inizializzare i tipi di valore, mentre newobj è usato per allocare e inizializzare oggetti. " Non c'è indicazione che chiami il costruttore predefinito di un tipo di riferimento.Presumo che sia equivalente a 'default (T)' – CodesInChaos

+0

@CodeInChaos: ho già cancellato il mio commento. Ho fatto un errore. – jason

+1

Ok, quindi la grande domanda è perché. Perché il compilatore non sta emettendo semplicemente un'istruzione 'newobj'? – jason

1

Sì. Lo fa per i tipi di riferimento.

Utilizzando ILSpy sul seguente codice di rilascio-compilato:

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

prodotto

.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 

O in C#:

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

JIT creerà diverse istruzioni compilate per ogni valore diverso digitare il parametro passato, ma utilizzerà le stesse istruzioni per i tipi di riferimento: lui nce Activator.CreateInstance()

+1

Vero anche per "Value Type" . 'Vedere pagina 544/capitolo 11 del libro -The C# Programming Language - 3rd Edition'. –

Problemi correlati