2012-06-21 17 views
9

Questo codice C# inutile:Perché il compilatore aggiunge un locale variabile

private void LoadAssignments(AssignmentType assignmentType, Collection<Assignment> assignments) 
    { 
     bool flag; 
     DataTable lessons = this.GetResults(assignmentType); 
     try 
     { 
      IEnumerator enumerator = lessons.Rows.GetEnumerator(); 
      try 
      { 
       while (true) 
       { 
        flag = enumerator.MoveNext(); 
        if (!flag) 
        { 
         break; 
        } 
        DataRow row = (DataRow)enumerator.Current; 
       } 
      } 
      finally 
      { 
       IDisposable disposable = enumerator as IDisposable; 
       flag = disposable == null; 
       if (!flag) 
       { 
        disposable.Dispose(); 
       } 
      } 
     } 
     finally 
     { 
      flag = lessons == null; 
      if (!flag) 
      { 
       lessons.Dispose(); 
      } 
     } 
    } 

produce questo CIL (NET 4)

.method private hidebysig 
    instance void LoadAssignments (
     valuetype TTReporterCore.AssignmentType assignmentType, 
     class [mscorlib]System.Collections.ObjectModel.Collection`1<valuetype TTReporterCore.Assignment> assignments 
    ) cil managed 
{ 
    .locals init (
     [0] bool flag, 
     [1] class [System.Data]System.Data.DataTable lessons, 
     [2] class [mscorlib]System.Collections.IEnumerator enumerator, 
     [3] class [System.Data]System.Data.DataRow row, 
     [4] class [mscorlib]System.IDisposable disposable, 
     [5] bool flag1 
    ) 

    IL_0000: nop 
    IL_0001: ldarg.0 
    IL_0002: ldarg.1 
    IL_0003: call instance class [System.Data]System.Data.DataTable TTReporterCore.TTReader::GetResults(valuetype TTReporterCore.AssignmentType) 
    IL_0008: stloc.1 
    .try 
    { 
     IL_0009: nop 
     IL_000a: ldloc.1 
     IL_000b: callvirt instance class [System.Data]System.Data.DataRowCollection [System.Data]System.Data.DataTable::get_Rows() 
     IL_0010: callvirt instance class [mscorlib]System.Collections.IEnumerator [System.Data]System.Data.InternalDataCollectionBase::GetEnumerator() 
     IL_0015: stloc.2 
     .try 
     { 
      IL_0016: nop 
      IL_0017: br.s IL_0038 
      .loop 
      { 
       IL_0019: nop 
       IL_001a: ldloc.2 
       IL_001b: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() 
       IL_0020: stloc.0 
       IL_0021: ldloc.0 
       IL_0022: stloc.s flag1 
       IL_0024: ldloc.s flag1 
       IL_0026: brtrue.s IL_002b 

       IL_0028: nop 
       IL_0029: br.s IL_003d 

       IL_002b: ldloc.2 
       IL_002c: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current() 
       IL_0031: castclass [System.Data]System.Data.DataRow 
       IL_0036: stloc.3 
       IL_0037: nop 

       IL_0038: ldc.i4.1 
       IL_0039: stloc.s flag1 
       IL_003b: br.s IL_0019 
      } 

      IL_003d: nop 
      IL_003e: leave.s IL_0062 
     } 
     finally 
     { 
      IL_0040: nop 
      IL_0041: ldloc.2 
      IL_0042: isinst [mscorlib]System.IDisposable 
      IL_0047: stloc.s disposable 
      IL_0049: ldloc.s disposable 
      IL_004b: ldnull 
      IL_004c: ceq 
      IL_004e: stloc.0 
      IL_004f: ldloc.0 
      IL_0050: stloc.s flag1 
      IL_0052: ldloc.s flag1 
      IL_0054: brtrue.s IL_0060 

      IL_0056: nop 
      IL_0057: ldloc.s disposable 
      IL_0059: callvirt instance void [mscorlib]System.IDisposable::Dispose() 
      IL_005e: nop 
      IL_005f: nop 

      IL_0060: nop 
      IL_0061: endfinally 
     } 

     IL_0062: nop 
     IL_0063: nop 
     IL_0064: leave.s IL_007e 
    } 
    finally 
    { 
     IL_0066: nop 
     IL_0067: ldloc.1 
     IL_0068: ldnull 
     IL_0069: ceq 
     IL_006b: stloc.0 
     IL_006c: ldloc.0 
     IL_006d: stloc.s flag1 
     IL_006f: ldloc.s flag1 
     IL_0071: brtrue.s IL_007c 

     IL_0073: nop 
     IL_0074: ldloc.1 
     IL_0075: callvirt instance void [System]System.ComponentModel.MarshalByValueComponent::Dispose() 
     IL_007a: nop 
     IL_007b: nop 

     IL_007c: nop 
     IL_007d: endfinally 
    } 

    IL_007e: nop 
    IL_007f: ret 
} 

Perché il MSIL aggiungere il flag1, continuare a svolgere le stessa logica per impostare il flag, impostare flag1 su flag e, infine, controllare! flag1. Questo mi sembra un'inefficienza del compilatore per me.

AGGIORNAMENTO: Stavo usando il JustDecompile di Telerik e mentre i risultati sono molto diversi da ILDASM, il booleano aggiuntivo viene ancora creato in modalità di debug.

Inoltre, ho modificato il codice rimuovendo completamente il valore booleano e la versione di debug aggiunge ancora un valore booleano. Sto davvero cercando il motivo per cui il compilatore fa questo.

+3

Cosa succede se si compila in modalità di rilascio anziché in modalità di debug? –

+0

Stesso risultato in modalità di rilascio. – kakridge

+0

Il nome della variabile effettiva è simile a "CS $ 4 $ 0000", non "flag1". E * * * viene ottimizzato nella versione di rilascio. Non sei sicuro di quale disassemblatore stai usando ma suona borken. Usa ildasm.exe per vedere questo. –

risposta

2

Sembra che venga creato un locale temporaneo per contenere i risultati del confronto (vale a dire monouso == nullo).

Cercando questo esempio:

class Program 
{ 
    static void Main() 
    { 
     if (1 == 1) return; 
    } 
} 

..è che producono il seguente IL sulla mia macchina (Microsoft (R) Visual C# 2010 Compiler versione 4.0.30319.1):

.method private hidebysig static void Main() cil managed 
{ 
    .entrypoint 
    .maxstack 1 
    .locals init (bool V_0) 
    IL_0000: nop 
    IL_0001: ldc.i4.0 
    IL_0002: stloc.0 
    IL_0003: br.s  IL_0005 
    IL_0005: ret 
} 

V_0 locale è creato, anche se in realtà non è usato. Credo che sia un'ovvia ottimizzazione anche per la compilazione non ottimizzata :) ... o più probabilmente: tutto il codice necessario viene generato per abilitare il debug. Non so come potrebbe essere usato in una sessione di debug, ma è la mia ipotesi migliore.

Quando compilato ottimizzato (ad esempio configurazione di rilascio) Non vedo il locale extra.

0

Quando ho scritto un programma simile, la variabile extra non è stata visualizzata in modalità di rilascio. Lo stesso in vista di assieme, il debug ha mostrato l'essere insieme variabile in più ([EBP-44h]) e il rilascio non fosse:

Debug:

enter image description here

di uscita:

enter image description here

+4

Sembra che tu abbia saltato la prima parola del titolo. –

Problemi correlati