12

在尝试了一个迭代器块后,我注意到生成的 IL 代码不是我所期望的。而不是 try-finally 块,而是生成了一个我从未见过的 try-fault 块。我注意到编译器不允许我在“手写”C# 中使用错误关键字。

2有区别吗?

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 处理程序。

4

1 回答 1

8

是的,Finally 块总是在帧退出时执行。只有当异常在帧之后展开时,才会执行故障块。MoveNext 中的故障块保留了从 ReadAllLines 迭代器的 try 块抛出异常的情况的使用语义。必须使用其他一些机制来保留从迭代器正常退出时的使用语义。

于 2009-08-01T22:33:47.087 回答