12

イテレータブロックを試した後、生成された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ハンドラーが指定されています。

4

1 に答える 1

8

はい、Finally ブロックは常にフレーム終了時に実行されます。フォルト ブロックは、例外がフレームを超えて巻き戻された場合にのみ実行されます。MoveNext の fault ブロックは、ReadAllLines イテレータの try ブロックから例外がスローされた場合の using セマンティクスを保持します。イテレータからの通常の終了時に using セマンティクスを保持するには、他のメカニズムを使用する必要があります。

于 2009-08-01T22:33:47.087 に答える