代码之家  ›  专栏  ›  技术社区  ›  Paul van Brenk

迭代器块在IL中生成try fault

  •  11
  • Paul van Brenk  · 技术社区  · 15 年前

    在试验了迭代器块之后,我注意到生成的IL代码并不是我期望的那样。不是生成一个try finally块,而是生成一个try故障块,这是我从未见过的。我注意到编译器不允许我在“手写”C_中使用fault关键字。

    二者有什么区别吗?

    C代码:

    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代码:

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

    有趣的一行是IL的最后一行,其中指定了一个错误处理程序,在普通的try finally块中指定了一个finally处理程序。

    1 回复  |  直到 9 年前
        1
  •  8
  •   Steve Steiner    15 年前

    是的,finally块总是在帧退出时执行。只有当异常在帧之后解除时,才会执行故障块。moveNext中的故障块保留了readAlllines迭代器的try块引发异常时的使用语义。必须使用其他一些机制来在从迭代器正常退出时保留使用语义。