2009-08-01 10 views
11

Nach dem Experimentieren mit einem Iterator-Block habe ich festgestellt, dass der generierte IL-Code nicht das ist, was ich erwarte. Anstelle eines try-finally-Blocks wird ein try-fault-Block generiert, den ich noch nie gesehen habe. Mir ist aufgefallen, dass der Compiler es nicht erlaubt, das Fehler-Schlüsselwort in 'handgeschriebenen' C# zu verwenden.Iterator-Block erzeugt Try-Fehler in IL

Gibt es einen Unterschied zwischen den 2?

C# -Code:

static IEnumerable<string> ReadAllLines(string fileName) 
{ 
    using (var file = System.IO.File.OpenText(fileName)) 
    { 
     string s; 
     while ((s = file.ReadLine()) != null) 
     { 
      yield return s; 
     } 
    } 
} 

MSIL Code:

.method private hidebysig newslot virtual final instance bool MoveNext() cil managed 
{ 
    .override [mscorlib]System.Collections.IEnumerator::MoveNext 
    .maxstack 3 
    .locals init (
     [0] bool CS$1$0000, 
     [1] int32 CS$4$0001, 
     [2] string CS$0$0002, 
     [3] bool CS$4$0003) 
    L_0000: ldarg.0 

    // try body 

    L_008d: leave.s L_0097 
    L_008f: ldarg.0 
    L_0090: call instance void ConsoleApplication2.Program/<ReadAllLines>d__0::System.IDisposable.Dispose() 
    L_0095: nop 
    L_0096: endfinally 
    L_0097: nop 
    L_0098: ldloc.0 
    L_0099: ret 
    .try L_0000 to L_008f fault handler L_008f to L_0097 
} 

Die interessante Zeile ist die letzte Zeile des IL, wo ein Fehler-Handler angegeben wird, wo in einem normalen try-finally ein Block Schließlich ist der Handler angegeben.

+1

Warum ist dies speziell mit .net-4.0 markiert? Hat sich das zwischen den Versionen geändert? –

Antwort

8

Ja, ein Finally-Block wird immer beim Frame-Exit ausgeführt. Ein Fehlerblock wird nur ausgeführt, wenn eine Ausnahme nach dem Rahmen abgewickelt wird. Der Fehlerblock in MoveNext bewahrt die using-Semantik für den Fall einer Ausnahme, die vom try-Block des ReadAllLines-Iterators ausgelöst wird. Ein anderer Mechanismus muss verwendet werden, um die using-Semantik beim normalen Beenden des Iterators beizubehalten.

+0

Das Dispose im Fehler wird also nur aufgerufen, wenn im Testteil eine Ausnahme behandelt wird. Und die regelmäßige Entsorgung wird von der Dispose-Methode des generierten IEnumerator behandelt. –