Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterator block generates try-fault in IL

Tags:

c#

.net

cil

After experimenting with an iterator block I noticed the generated IL code is not what I expect it to be. Instead of a try-finally block a try-fault block is generated, which I have never seen. I noticed that the compiler doesn't allow me use the fault keyword in 'handwritten' C#.

Is there any difference between the 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
}

The interesting line is the last line of the IL where a fault handler is specified, where in a normal try-finally block a finally handler is specified.

like image 286
Paul van Brenk Avatar asked Aug 01 '09 22:08

Paul van Brenk


1 Answers

Yes, a Finally block always executes on frame exit. A fault block executes only if an exception is unwound past the frame. The fault block in MoveNext preserves the using semantics for the case of an exception thrown from the try block of the ReadAllLines iterator. Some other mechanism must be in use to preserve the using semantics on normal exit from the iterator.

like image 73
Steve Steiner Avatar answered Nov 12 '22 15:11

Steve Steiner