C#を使用した開発において、配列やリストなどのコレクションを順番に処理するforeach文は非常に頻繁に利用されます。
通常、foreach文はすべての要素を走査しますが、特定の条件を満たした時点で処理を切り上げたいケースも少なくありません。
このような場面で不可欠なのがbreak文によるループの中断です。
本記事では、C#のforeach文でbreakを使用する方法を、初心者にも分かりやすく解説します。
また、混同しやすいcontinue文との違いや、多重ループにおける注意点、さらには実戦で役立つ応用テクニックまで詳しく網羅しました。
効率的なコーディングスキルを身につけるための参考にしてください。
C#のforeach文におけるbreakの役割
C#のforeach文は、コレクション内の要素を一つずつ取り出して処理を行う反復ステートメントです。
通常、コレクションの末尾に到達するまでループは継続されますが、特定の条件に合致した瞬間にループ全体を終了させたい場合にbreak文を使用します。
break文が実行されると、ループ内の残りの処理および、まだ取り出されていない要素の反復処理はすべてスキップされ、プログラムの制御はforeachブロックの直後の命令へと移ります。
これにより、不要な計算リソースの消費を抑え、プログラムの実行速度を向上させることが可能です。
基本的な構文と動作
foreach文の中でif文などの条件分岐と組み合わせてbreakを記述するのが一般的な形です。
foreach (var item in collection)
{
if (中断条件)
{
// ループを直ちに終了する
break;
}
// 中断条件に合致しない場合の処理
}
具体的なサンプルコード
以下のプログラムは、整数のリストから特定の数値を探し、見つかった時点でループを抜ける例です。
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<int> numbers = new List<int> { 10, 25, 40, 55, 70, 85, 100 };
int target = 55;
Console.WriteLine("探索を開始します。");
foreach (int num in numbers)
{
Console.WriteLine($"現在の値: {num}");
if (num == target)
{
// ターゲットが見つかったのでループを中断
Console.WriteLine($"{target} が見つかりました。処理を中断します。");
break;
}
}
Console.WriteLine("foreach文の外に抜けました。");
}
}
探索を開始します。
現在の値: 10
現在の値: 25
現在の値: 40
現在の値: 55
55 が見つかりました。処理を中断します。
foreach文の外に抜けました。
この例では、リストの中に「100」まで要素がありますが、「55」に到達した時点でループが終了していることがわかります。
残りの「70, 85, 100」の処理は行われません。
breakとcontinueの決定的な違い
break文と並んでよく使われるのがcontinue文です。
これらはどちらもループの流れを制御するものですが、その効果は大きく異なります。
continue文の動作
continue文は、「現在の反復処理のみをスキップし、次の要素の処理へ進む」ために使用されます。
ループ自体を終了させるわけではなく、あくまで「今の回」を飛ばすだけです。
比較表による整理
両者の違いを理解するために、以下の表にまとめました。
| 項目 | break文 | continue文 |
|---|---|---|
| 主な目的 | ループ全体の強制終了 | 現在の回の処理をスキップして次へ |
| 実行後の動き | 閉じる中カッコ } の次へ移動 | ループの先頭(次の要素取得)へ移動 |
| 残りの要素 | 処理されない | 処理される |
| 主な用途 | 検索完了時、異常検知時 | 特定条件のデータを除外したい時 |
以下のコードで、挙動の違いを確認してみましょう。
using System;
class Program
{
static void Main()
{
int[] data = { 1, 2, 3, 4, 5 };
Console.WriteLine("--- breakの動作 ---");
foreach (int i in data)
{
if (i == 3) break;
Console.WriteLine(i);
}
Console.WriteLine("--- continueの動作 ---");
foreach (int i in data)
{
if (i == 3) continue;
Console.WriteLine(i);
}
}
}
--- breakの動作 ---
1
2
--- continueの動作 ---
1
2
4
5
breakは「3」が出た瞬間に終わりますが、continueは「3」だけを飛ばして「4」と「5」の処理を継続しています。
ネスト(入れ子)構造におけるbreakの挙動
複雑なプログラムでは、foreach文の中にさらに別のforeach文やfor文が記述される「ネスト」の状態になることがあります。
ここで注意が必要なのは、break文は「現在実行されている最も内側のループ」しか脱出できないという点です。
外側のループも抜けたい場合
内側のループで条件を満たした際、外側のループまで一気に抜けたい場合には工夫が必要です。
主に以下の3つの方法が検討されます。
- フラグ変数を使用する: 内側でフラグを立て、外側でもそのフラグをチェックして
breakする。 - return文を使用する: 処理自体がメソッドとして独立しているなら、
returnでメソッドごと終了する。 - LINQを使用する: データを平坦化してから処理する。
以下はフラグ変数を用いた例です。
using System;
class Program
{
static void Main()
{
string[][] matrix = {
new string[] { "A1", "A2", "A3" },
new string[] { "B1", "TARGET", "B3" },
new string[] { "C1", "C2", "C3" }
};
bool found = false;
foreach (var row in matrix)
{
foreach (var cell in row)
{
if (cell == "TARGET")
{
Console.WriteLine("ターゲットを発見しました。");
found = true;
break; // 内側のループを抜ける
}
Console.WriteLine($"探索中: {cell}");
}
if (found)
{
// フラグが立っていれば外側のループも抜ける
break;
}
}
Console.WriteLine("全探索を終了しました。");
}
}
探索中: A1
探索中: A2
探索中: A3
探索中: B1
ターゲットを発見しました。
全探索を終了しました。
foreachとbreakの活用シーン
実務においてforeachとbreakを組み合わせるパターンは定型化されています。
代表的なケースを見ていきましょう。
検索処理の最適化
最も一般的な用途は、大量のデータから特定の条件に合うものを1つだけ探すケースです。
例えば、ユーザーリストからIDが一致するユーザーを検索する場合、見つかった後に残りの数万件をループさせるのは非常に非効率です。
見つかった瞬間にbreakさせることで、計算リソースを劇的に節約できます。
エラー検知時の即時中断
複数のファイルを順番にアップロードするようなバッチ処理において、1つでも致命的なエラーが発生したら後続の処理を中止したい場合があります。
このような際、try-catchとbreakを組み合わせて使用します。
foreach (var file in files)
{
bool success = UploadFile(file);
if (!success)
{
Console.WriteLine("アップロードに失敗したため、以降の処理を中止します。");
break;
}
}
モダンなC#におけるLINQとの使い分け
近年のC#開発では、foreachとbreakを使った命令的な記述の代わりに、LINQ (Language Integrated Query)を用いた宣言的な記述が好まれる傾向にあります。
例えば、「リストから最初の偶数を見つける」という処理は、以下のように書き換えられます。
従来の方式:
int firstEven = -1;
foreach (int n in numbers)
{
if (n % 2 == 0)
{
firstEven = n;
break;
}
}
LINQを使用した方式:
using System.Linq;
// ...
int firstEven = numbers.FirstOrDefault(n => n % 2 == 0);
LINQのFirstOrDefaultやAny、Takeといったメソッドは、内部的に効率的なループ処理を行っており、条件を満たした時点で列挙を停止する(遅延評価)性質を持っています。
コードの可読性が高まるため、単純な検索やフィルタリングであればLINQの利用を検討すべきです。
ただし、ループ内で行う処理が複雑であったり、複数の副作用(ログ出力や状態更新など)を伴う場合は、依然としてforeach文とbreakを組み合わせる方が、デバッグしやすく分かりやすいコードになることもあります。
状況に応じて最適な手法を選択することが重要です。
まとめ
C#のforeach文におけるbreakは、ループ処理の制御を柔軟に行うための基本かつ強力なツールです。
- break文は、ループ全体をその場で即座に終了させる。
- continue文は、現在の反復だけをスキップして次の要素へ進む。
- ネスト構造では、最も内側のループのみが対象となるため、多重ループ脱出にはフラグ管理などが必要。
- シンプルな検索処理には、LINQによる代替も検討する。
これらの特性を正しく理解し、適切に使い分けることで、バグの少ない、そしてパフォーマンスに優れたC#プログラムを記述できるようになります。
ループ処理はプログラミングの根幹を成す要素ですので、ぜひこの機会にマスターしてください。






