Iteratorblock erzeugt versuchen-fault in IL
Frage
Nach dem mit einem Iteratorblock experimentieren bemerkte ich das erzeugte IL-Code ist nicht das, was ich erwarte, dass es sein. Statt einem Try-finally-Block Try-Fehlerblock erzeugt wird, die ich noch nie gesehen. Ich bemerkte, dass der Compiler nicht erlaubt ich in ‚handschriftlich‘ C #, um den Fehler Schlüsselwort.
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 Handler angegeben ist.
Lösung
Ja, ein Finally-Block führt immer am Rahmen zu verlassen. Ein Fehlerblock wird nur ausgeführt, wenn eine Ausnahme hinter dem Rahmen abgewickelt wird. Der Fehlerblock in Movenext bewahrt die Verwendung von Semantik für den Fall einer Ausnahme von dem Try-Block des Iterators ReadAllLines geworfen. Ein anderer Mechanismus in Gebrauch sein muss, die mit Semantik auf normalen Austritt aus dem Iterator zu bewahren.