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

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

有帮助吗?

解决方案

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top