Menu

C#のbreak、continue、goto:ループと多重ループから抜ける

C#のbreak、continue、gotoの動き方を解説します。ループを早めに終える方法、反復を飛ばす方法、switchの中のbreak、多重ループから抜ける3つの方法(フラグ、goto、returnを使うメソッド)、そしてwhileの中のcontinueによる無限ループのバグを扱います。

このページのコードはエディタで実行できます - 編集してすぐに結果を確認できます。

break はループを早めに終わらせます。continue は現在の反復の残りを飛ばして次の反復へ進みます。どちらも最も内側のループに作用し、for、foreach、while、do while で同じように動きます。

出力:

process order of 45
skip invalid total 0
process order of 120
skip invalid total -5
process order of 80
test order found, stopping
after the loop

continue は 0 と -5 のときに処理の行を飛ばしました。break は 999 でループを止めたので、60 は訪れられず、実行はループの後の最初の文から再開しました。

break:答えがわかったら止める

break の典型的な使い方は探索です。探していたものが見つかったら、残りを見る理由はありません。

出力:

first invalid email at index 1

break の後に反復子(i++)は実行されないので、i をループの外で宣言していれば、一致したインデックスがそのまま残ります。単純な探索なら、ライブラリの呼び出しでも同じことを表せます。Array.FindIndex(emails, e => !e.Contains("@")) はインデックス(または-1)を返し、LINQの emails.Any(e => !e.Contains("@")) は不正なものが存在するかどうかを答えます。

continue:次の反復へ進む

continue はループのためのガード節です。本来の処理を if で囲む代わりに、不要なケースを先頭で弾きます。

出力:

pen costs 1.20
mug costs 8.00

continue の次にどこへ進むかはループによって異なります。for ループでは反復子を実行してから条件を判定します。while ループでは条件へ直接ジャンプするので、典型的なバグにつながります。

int i = 0;
while (i < 10)
{
    if (i % 2 == 0)
        continue;        // i++ below is skipped: i stays 0 forever
    Console.WriteLine(i);
    i++;
}

continue の前にカウンターを更新するか、更新がヘッダーにあって必ず実行される for ループを使います。

ループの中のswitchの中のbreak

switch の中では、break はcaseのセクションを終わらせます。その switch がループの中にあるとき、break はループではなくswitchに属します。

出力:

quit received
count = 2

"quit" のcaseがただの break だったら、switchが終わるだけでループは続き、count は3になっていたはずです。goto はループの後のラベルへジャンプします。ループをメソッドに移してそのcaseで return を書く方法でも動き、ラベルは不要です。

多重ループから抜ける

C#には、Javaの break outer; のようなラベル付きの break はありません。2重のループで探索するとき、内側のループでの break は内側のループを終わらせるだけで、外側のループは次の行へ進みます。標準的な直し方は3つあります。

1. フラグを外側のループで判定する:

出力:

first free seat: row 1, seat 2

2. goto で両方のループの後のラベルへ飛ぶ。「両方のループから抜ける」をそのまま表現するので、多くのC#のスタイルガイドが goto を認める唯一の場面です。

for (int row = 0; row < rows; row++)
{
    for (int col = 0; col < cols; col++)
    {
        if (seats[row, col] == 0)
        {
            Console.WriteLine($"first free seat: row {row}, seat {col}");
            goto done;
        }
    }
}
done:
Console.WriteLine("search finished");

3. returnを使うメソッド。探索に名前が付き、結果を返せるので、たいてい最もすっきりします。

出力:

first free seat: row 1, seat 2

C# 7.0ではローカル関数も導入され、このヘルパーメソッドを呼び出し元のメソッドの中に置けるようになりました。ここで使ったoutパラメーターの形はrefとoutのページで説明しています。

gotoとラベル

ラベルは識別子の後にコロンを付けたもので、goto label; でそこへジャンプします。ルールは厳しく、最悪の誤用を防げるようになっています。

  • ラベルは同じメソッド内で、goto と同じブロックかそれを囲むブロックになければなりません。ブロックの外へはジャンプできますが、中へは決してジャンプできません。外側からループの本体の中のラベルへジャンプすると、エラーCS0159(gotoステートメントのスコープ内にそのようなラベルがない)になります。
  • goto、break、continue で finally ブロックから抜けることはできません。
  • switch の中では、goto case 3; と goto default; で別のセクションへ制御を移します。次のcaseへ暗黙に流れ込むとコンパイルエラーになるので、C#のswitchはこの方法でフォールスルーを表現します。

goto で(ラベルへ後ろ向きにジャンプして)ループを作ることもできますが、while ループなら同じことを誰でも見慣れた形で表せます。goto は多重ループから抜ける場合とswitchのセクションに限って使います。

return、throwとループ

return はメソッド全体から抜けるので、その中のすべてのループからも抜けます。throw も例外を発生させることで同じことをします。finally 付きの try ブロックの中では、break、continue、goto、return のどれでも、制御が移る前に finally ブロックが実行されます。だから、using ブロックでファイルを開いたままのループからでも安全に抜けられます。

文抜けるもの続きの場所
continue現在の反復次の反復(反復子、次に条件)
break最も内側のループまたはswitchその後の文
goto labelそれを囲む任意のブロックラベル
returnメソッド呼び出し元
throw一致する catch までのすべてcatch ブロック

よくある質問

C#のbreakとcontinueの違いは何ですか?

break は最も内側のループ(または switch)をすぐに終わらせ、実行はその後から続きます。continue は現在の反復だけを終わらせて次の反復へ進みます。for ループでは次に反復子が実行され、while と do while では次に条件が判定され、foreach では次の要素が取得されます。

C#で多重ループから抜けるには?

C#にはラベル付きの break はありません。選択肢は3つです。bool のフラグを立てて外側のループで判定する、goto で両方のループの後のラベルへジャンプする、ループをメソッドに移してそこから return する。メソッドにする方法がたいてい最もすっきりしています。探索に名前と戻り値も与えられるからです。

C#でswitchの中のbreakはループから抜けますか?

抜けません。ループの中にある switch では、break は switch のセクションを終わらせるだけで、ループは続きます。caseの中からループを抜けるには、return、switchの後で判定するフラグ、またはループの後のラベルへの goto を使います。caseの中の continue は、ループの次の反復へ進みます。

C#でgotoは使えますか?

使えます。goto label; は同じメソッド内の label: へジャンプしますが、ブロックの中へジャンプすることや、finally から抜け出すことはできません。switch の中では、goto case value; と goto default; でセクション間をジャンプします。多重ループから抜ける場合とswitchの明示的なフォールスルー以外では、gotoが最も明確な選択になることはまれです。

Coddy programming languages illustration

Coddyでコードを学ぼう

始める