2012-06-21 5 views
9

Diese C# -Code:Warum kommt In der Compiler eine Unnötige Lokale Variable

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(); 
      } 
     } 
    } 

produziert diese 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 
} 

Warum die MSIL die flag1 hinzufügen, weiterhin die auszuführen gleiche Logik, um Flag zu setzen, setze flag1 auf flag und überprüfe schließlich! flag1. Das scheint mir eine Compiler-Ineffizienz zu sein.

UPDATE: Ich habe Teleriks JustDecompile verwendet, und während die Ergebnisse von ILDASM ziemlich verschieden sind, wird der zusätzliche boolean noch im Debug-Modus erstellt.

Außerdem habe ich den Code durch Entfernen der Boolean vollständig geändert und die Debug-Version fügt noch einen Boolean. Ich suche wirklich, warum der Compiler das tut.

+3

Was passiert, wenn Sie im Release-Modus statt im Debug-Modus kompilieren? –

+0

Gleiches Ergebnis im Freigabemodus. – kakridge

+0

Der tatsächliche Variablenname ähnelt "CS $ 4 $ 0000", nicht "flag1". Und es wird * im Release-Build optimiert. Nicht sicher, welchen Disassembler Sie verwenden, aber es klingt borken. Verwenden Sie ildasm.exe, um dies zu sehen. –

Antwort

2

Es scheint, als ob eine temporäre lokale erstellt wird, um die Ergebnisse des Vergleichs (dh Einweg == Null).

Der Versuch, dieses Beispiel:

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

..ist das folgende IL auf meiner Box (Microsoft (R) Visual C# 2010-Compiler Version 4.0.30319.1) Herstellung:

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

lokale V_0 ist erstellt, obwohl es eigentlich nicht verwendet wird. Ich glaube, es ist eine offensichtliche Optimierung sogar für "nicht" optimierte Kompilierung :) ..oder wahrscheinlicher: der gesamte notwendige Code wird erzeugt, um das Debuggen zu ermöglichen. Ich weiß nicht, wie es in einer Debugging-Sitzung verwendet werden könnte, aber es ist meine beste Schätzung.

Wenn kompiliert optimiert (d. H. Release-Konfiguration) Ich sehe nicht die zusätzliche lokale.

0

Wenn ich ein ähnliches Programm schrieb, erschien die Extra-Variable nicht im Freigabemodus. Gleiche in Montageansicht, zeigte das Debuggen die zusätzliche Variable gesetzt wird ([EBP-44h]) und nicht loslassen:

Debug:

enter image description here

Release:

enter image description here

+4

Sie scheinen das erste Wort des Titels übersprungen zu haben. –

Verwandte Themen