迭代器块在IL中生成try-fault

Pau*_*enk 12 .net c# cil

在尝试使用迭代器块之后,我注意到生成的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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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
}
Run Code Online (Sandbox Code Playgroud)

有趣的行是指定了错误处理程序的IL的最后一行,其中在正常的try-finally块中指定了finally处理程序.

Ste*_*ner 8

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