108

問題ありません。私はただ興味があります。次のシナリオを想像してください。

foreach (var foo in list)
{
    try
    {
         //Some code
    }
    catch (Exception)
    {
        //Some more code
    }
    finally
    {
        continue;
    }
}

コンパイラ エラー CS0157が発生するため、これはコンパイルされません。

コントロールは、finally 句の本体を離れることはできません

なんで?

4

11 に答える 11

16

他の人が述べているように、例外に焦点を当てていますが、それは実際には制御を移すあいまいな処理に関するものです。

頭の中で、おそらく次のようなシナリオを考えているでしょう。

public static object SafeMethod()
{
    foreach(var item in list)
    {
        try
        {
            try
            {
                //do something that won't transfer control outside
            }
            catch
            {
                //catch everything to not throw exceptions
            }
        }
        finally
        {
            if (someCondition)
                //no exception will be thrown, 
                //so theoretically this could work
                continue;
        }
    }

    return someValue;
}

理論的には、制御フローを追跡して、「はい、これで問題ありません」と言うことができます。例外はスローされず、制御は転送されません。しかし、C# 言語の設計者は別の問題を念頭に置いていました。

スローされた例外

public static void Exception()
{
    try
    {
        foreach(var item in list)
        {
            try
            {
                throw new Exception("What now?");
            }
            finally
            {
                continue;
            }
        }
    }
    catch
    {
        //do I get hit?
    }
}

恐怖の後藤

public static void Goto()
{
    foreach(var item in list)
    {
        try
        {
            goto pigsfly;
        }
        finally
        {
            continue;
        }
    }

    pigsfly:
}

リターン

public static object ReturnSomething()
{
    foreach(var item in list)
    {
        try
        {
            return item;
        }
        finally
        {
            continue;
        }
    }
}

分裂

public static void Break()
{
    foreach(var item in list)
    {
        try
        {
            break;
        }
        finally
        {
            continue;
        }
    }
}

結論として、はい、コントロールが転送されていない状況でa を使用する可能性はわずかありますが、continue多くの (大多数?) ケースには例外またはreturnブロックが含まれます。言語設計者は、これはあまりにも曖昧であり、制御フローが転送されていない場合にのみcontinue使用されることをコンパイル時に保証することは (おそらく) 不可能であると感じました。

于 2013-08-01T10:40:10.400 に答える
11

一般に、ブロックcontinueで使用すると意味がありません。finallyこれを見てください:

foreach (var item in list)
{
    try
    {
        throw new Exception();
    }
    finally{
        //doesn't make sense as we are after exception
        continue;
    }
}
于 2013-08-01T10:12:06.037 に答える
3

finally ブロックの本体を離れることはできません。これには、break、return、およびあなたの場合は continue キーワードが含まれます。

于 2013-08-01T10:12:06.887 に答える
1

技術的に言えば、これは基盤となる CIL の制限です。言語仕様から:

コントロール転送は、例外処理メカニズムを介する場合を除き、catch ハンドラーまたは finally 句に入ることは許可されません。

leave保護領域からの制御転送は、例外命令 ( 、end.filterend.catch、またはend.finally)を介してのみ許可されます。

br命令のドキュメントページで:

この命令では、try、catch、filter、および finally ブロックへの制御転送は実行できません。

これは、、 などを含むすべての分岐命令に当てはまります。beqbrfalse

于 2013-08-01T20:07:13.313 に答える
-1

この言語の設計者は、finally ブロックのセマンティクスが制御転送によって終了することについて、推論したくありませんでした (または、推論できませんでした)。

1 つの問題、またはおそらく重要な問題は、finallyブロックが非ローカル制御転送 (例外処理) の一部として実行されることです。その制御転送のターゲットは、囲んでいるループではありません。例外処理はループを中止し、さらに巻き戻しを続けます。

クリーンアップ ブロックからのコントロールfinallyトランスファーがある場合、元のコントロール トランスファーは「ハイジャック」されています。キャンセルされ、制御が別の場所に移動します。

セマンティクスは解決できます。他の言語にはそれがあります。

C# の設計者は、静的な「goto のような」制御転送を単純に禁止することを決定し、それによって物事をいくらか単純化しました。

ただし、それを行っても、動的転送が a から開始された場合に何が起こるかという問題は解決しませんfinally。その後、元の例外処理が「ハイジャック」されます。

この 2 番目の形式のハイジャックのセマンティクスを解明した場合、最初の種類のハイジャックを追放する理由はありません。それらは実際には同じものです。つまり、レキシカル スコープが同じであるかどうかに関係なく、コントロール トランスファーはコントロール トランスファーです。

于 2013-08-01T18:25:07.137 に答える