Frage

Ich schrieb eine ziemlich komplexe Methode, die Ausbeute-returns IEnumerable<string>, aber wenn ich die Compilerausgabe in Reflector inspizierte, ich verstand nicht, einen bestimmten Teil der Compiler generierten Implementierung von IEnumerator:

void IDisposable.Dispose()
{
    switch (this.<>1__state)
    {
        case 1:
        case 2:
        case 3:
            switch (this.<>1__state) // empty switch! why?!
            {
            }
            break;

        default:
            return;
            try   // What?! AFTER return?!
            {
            }
            finally // is the try-finally block anyhow relevant?
            {
                this.<>m__Finallya();
            }
            break;
    }
    this.<>m__Finally7();
}

Ich vermute (oder gehofft), dass Reflector die schließende Klammer des äußeren switch verlegt wird, und dass sie direkt nach dem return sein. Trotzdem verstehe ich nicht, warum es ein leerer Schalter in Fall 3, oder warum m__Finallya in einem finally Block aufgerufen wird. (Gibt es einen semantischen Unterschied zwischen normal läuft und in einem finally Block? Anders' als CERs, die ich nicht habe in meinem Code.)

Als Referenz ist hier die IL:

.method private hidebysig newslot virtual final 
        instance void  System.IDisposable.Dispose() cil managed
{
  .override [mscorlib]System.IDisposable::Dispose
  // Code size       69 (0x45)
  .maxstack  2
  .locals init ([0] int32 CS$0$0000,
           [1] int32 CS$0$0001)
  IL_0000:  ldarg.0
  IL_0001:  ldfld      int32 FBD.TIP.Reader.MissingMessagesReader/'<GetMissingMessages>d__0'::'<>1__state'
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  ldc.i4.1
  IL_0009:  sub
  IL_000a:  switch     ( 
                        IL_001c,
                        IL_001c,
                        IL_001c)
  IL_001b:  ret
  IL_001c:  ldarg.0
  IL_001d:  ldfld      int32 FBD.TIP.Reader.MissingMessagesReader/'<GetMissingMessages>d__0'::'<>1__state'
  IL_0022:  stloc.1
  IL_0023:  ldloc.1
  IL_0024:  ldc.i4.2
  IL_0025:  sub
  IL_0026:  switch     ( 
                        IL_0035,
                        IL_0035)
  IL_0033:  br.s       IL_003e
  .try
  {
    IL_0035:  leave.s    IL_003e
  }  // end .try
  finally
  {
    IL_0037:  ldarg.0
    IL_0038:  call       instance void FBD.TIP.Reader.MissingMessagesReader/'<GetMissingMessages>d__0'::'<>m__Finallya'()
    IL_003d:  endfinally
  }  // end handler
  IL_003e:  ldarg.0
  IL_003f:  call       instance void FBD.TIP.Reader.MissingMessagesReader/'<GetMissingMessages>d__0'::'<>m__Finally7'()
  IL_0044:  ret
} // end of method '<GetMissingMessages>d__0'::System.IDisposable.Dispose
War es hilfreich?

Lösung

Das ist einfach zu kämpfen Reflektor mit dem IL Schritt zu halten, die erzeugt wurde (seit Iterator Blöcke müssen so lange zu „normalen“ C # nicht betreffen, da sie IL gelten). Insbesondere ist die ret nach dem finally Block.

Andere Tipps

Sie haben nicht gezeigt, was Ihre ursprüngliche Iteratorblock aussieht, aber meine Erfahrung von Reflektor und Compiler generierte Code ist, dass es nicht immer gelingt ganz genau zu dekompilieren, weil der Compiler einige IL verwendet, die nicht existiert ein Äquivalent in C #.

Ich habe einen Artikel über Iteratorblock Implementierung habe, die Ihnen ein wenig helfen können , aber ich würde nicht zu viel Sorgen darüber, was der kompilierte Code aussieht. In einigen Fällen wird die C # -Compiler Erzeugung an Sicherheit grenzender Wahrscheinlichkeit unnötigen Code mit der Begründung, das hält den Compiler einfacher. Iterator Blöcke muss sehr heikel gewesen richtig zu machen (es kann sehr kompliziert werden, mit schließlich Blöcken und Iterator zur Verfügung), so halte ich es für sinnvoll ist nur der JIT zu vertrauen, die unnötigen Bits wie der Schalter / Fall in Ihrem generierten Code zu optimieren entfernt.

Ich könnte argumentieren, dass der C # -Compiler ist dumm, (es ist wahrscheinlich ein bisschen dumm ist). Es ist auch durchaus möglich, dass dieser Code ganz anders aussieht, wenn sie von der Laufzeit (alles, was böser Müll weggelassen wird).

jitted

Wie auch immer, Sie vielleicht mit State-Maschinen vertraut? Wenn Sie Generatoren in C # (Ausbeute Zeug) schreiben Sie den Compiler sagen einen anonymen Typ zu emittieren, die diesen Generator als eine Zustandsmaschine implementiert. Dies ist ein schöner formaler Ansatz, der nachprüfbar sein sollte. Das ist wahrscheinlich der Grund, warum es so aussieht, es funktioniert.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top