プログラムが「ある条件の間だけ」処理を繰り返すとき、C#ではwhile文が最もシンプルな選択肢です。
条件が真の間だけ回り続け、偽になった瞬間に止まります。
本稿では、基本構文からサンプル、制御のコツ、無限ループ回避、for/do-whileとの使い分けまで丁寧に解説します。
C#のwhile文(whileループ)とは?
while文は「事前判定ループ」です。
ループの先頭で条件式を評価し、真の間だけ本文を繰り返します。
条件が初回から偽であれば本文は一度も実行されません。
条件が動的に変わる処理(ユーザー入力、データの到着待ち、状態が整うまでの待機など)に向いています。
どんなときに使う?
- 終了条件がカウンタの上限ではなく、外部状態や検証結果に依存する場合
- 入力の妥当性検証を繰り返す UI/CLI
- ストリーム読み取りやキュー監視のような「ある間は処理する」用途
C#のwhile文の基本構文と書き方
while文の構文テンプレート(基本形)
条件式はboolに評価される式でなければなりません。
本文のどこかで条件が変化するように書きます。
// 基本形:条件が true の間、本文を繰り返します。
while (条件式)
{
// 繰り返したい処理
// ループを前進させるための更新(カウンタ、状態、入力など)
}
最小例:3回だけ挨拶する
int count = 0; // カウンタの初期化
while (count < 3) // 条件式:count が 3 未満の間
{
Console.WriteLine($"Hello {count}");
count++; // 状態更新:これを忘れると無限ループになります
}
Hello 0
Hello 1
Hello 2
条件式に使う比較演算子・論理演算子のポイント
条件式では比較演算子と論理演算子を組み合わせて判定します。
短絡評価(ショートサーキット)を理解しておくと安全です。
よく使う演算子の概要
種類 | 演算子 | 説明 | 例 |
---|---|---|---|
比較 | == | 等しい | x == 10 |
比較 | != | 等しくない | x != 0 |
比較 | <, <= | より小さい、以下 | x < 100, x <= max |
比較 | >, >= | より大きい、以上 | x > 0, x >= min |
論理 | && | 論理積(かつ、短絡評価) | a && b |
論理 | || | 論理和(または、短絡評価) | a || b |
論理 | ! | 否定 | !isDone |
- 短絡評価とは、左辺で結果が確定すれば右辺を評価しない性質です。例えば
file != null && file.Exists
と書けば、file
が null のときにExists
を呼ばないため安全です。 - 比較は数値だけでなく、文字・文字列・boolにも使えます(文字列の辞書順比較は
string.Compare
を使うとより明示的です)。
カウンタや状態の更新位置(無限ループを避けるコツ)
whileの本文では「いつ、どこで」状態が変わるかを明確にします。
基本は以下の流れです。
- 条件式で「入るか」を判定
- 本文の先頭で必要なガード(早期continue/breakなど)
- 本処理
- 次の判定が変わるように更新(カウンタ+1、入力の再取得など)
更新は本文の最後に置くのが読みやすいですが、処理の意味に応じて先頭で行う方が自然な場合もあります。
いずれにせよ「ループ1回で最低1つは条件に影響する変更が起こる」ことを自分に約束すると無限ループの大半を避けられます。
C# while文のサンプルコード
カウンタで0からNまで繰り返す基本サンプルコード
0からNまでの値を出力する最小構成です。
Nはユーザーから取得します。
// 0 から N まで(N を含む)を出力するサンプル
Console.Write("N を入力してください(例: 5):");
string? input = Console.ReadLine();
if (int.TryParse(input, out int N) && N >= 0)
{
int i = 0; // 開始値
while (i <= N) // 終了条件は「i が N 以下の間」
{
Console.WriteLine(i);
i++; // 次へ進める
}
}
else
{
Console.WriteLine("非負の整数を入力してください。");
}
N を入力してください(例: 5):5
0
1
2
3
4
5
オフバイワンに注意
<
と <=
の選び間違いが典型的です。
0..N を含めたいなら i <= N
、含めたくないなら i < N
とします。
条件に合うまでユーザー入力を繰り返し検証する例
1〜10の整数を受け付けるまで聞き続けます。
int.TryParse
を使うと例外を避けつつ安全に解析できます。
// 1〜10 の整数が入力されるまで繰り返す
int value;
while (true) // いったん無限ループにして中で抜けるパターン
{
Console.Write("1〜10 の整数を入力してください:");
string? s = Console.ReadLine();
// 数値かつ範囲内かをチェック
if (int.TryParse(s, out value) && value >= 1 && value <= 10)
{
break; // 条件を満たしたのでループ終了
}
Console.WriteLine("入力が不正です。もう一度お試しください。");
}
Console.WriteLine($"入力値は {value} です。");
1〜10 の整数を入力してください:abc
入力が不正です。もう一度お試しください。
1〜10 の整数を入力してください:15
入力が不正です。もう一度お試しください。
1〜10 の整数を入力してください:7
入力値は 7 です。
無限ループ+breakのスタイルについて
外側の条件が複雑になりがちな入力検証では、while (true)
と break
で明確に抜ける条件を1カ所に集約するのは読みやすさの面で有効です。
リストや配列の走査をwhileで行うシンプルな例
インデックスで進める典型的なパターンです。
forでも書けますが、whileにすると終了条件が柔軟に書けます。
// 配列の要素を while で順に出力する
string[] fruits = { "Apple", "Banana", "Cherry" };
int index = 0;
while (index < fruits.Length) // 範囲チェックを条件に
{
Console.WriteLine($"{index}: {fruits[index]}");
// 例えば特定の要素が見つかったら早期に抜ける
if (fruits[index] == "Banana")
{
Console.WriteLine("Banana を見つけました。検索を終了します。");
break;
}
index++; // インデックスを進める
}
0: Apple
1: Banana
Banana を見つけました。検索を終了します。
whileループの制御
breakでループを終了するタイミングの設計
break
は「今のループをただちに抜ける」命令です。
見つかったら終了する検索、エラー発生時の中断などに適しています。
// 目標値を見つけたらループを終了する
int[] numbers = { 2, 4, 6, 8, 10 };
int target = 6;
int pos = -1;
int i = 0;
while (i < numbers.Length)
{
if (numbers[i] == target)
{
pos = i;
break; // 目的達成:ここで抜ける
}
i++;
}
Console.WriteLine(pos >= 0 ? $"見つかりました: index={pos}" : "見つかりませんでした");
見つかりました: index=2
ガード節としてのbreak
ループ先頭に「成立しなければ続ける」ではなく「成立したら終える」を置くと、ネストを浅く保てます。
continueで処理をスキップする実用パターン
continue
は「残りの本文をスキップして次の反復に進む」命令です。
フィルタリングやエラーデータのスキップに適しています。
// 1〜20 のうち、偶数だけを出力する
int n = 1;
while (n <= 20)
{
if (n % 2 != 0)
{
n++; // 忘れずに前進させる
continue; // 奇数はスキップ
}
Console.WriteLine(n); // 偶数だけがここに到達
n++;
}
2
4
6
8
10
12
14
16
18
20
continueを使うときの注意
スキップする分岐の中でも前進のための更新(カウンタや状態)を忘れないようにします。
忘れると特定の値で永久にスキップし続け、無限ループになります。
boolフラグや複合条件でループ条件を安全に管理する
複数の終了条件がある場合は「継続条件」をANDで束ねると読みやすく、安全です。
// 条件:処理を続ける意思があり、かつエラーではなく、かつ試行回数の上限未満
bool isRunning = true;
bool hasError = false;
int attempts = 0;
int maxAttempts = 3;
while (isRunning && !hasError && attempts < maxAttempts)
{
attempts++;
// 仮の処理(ここで isRunning / hasError が変化する可能性がある)
bool ok = DateTime.Now.Second % 2 == 0; // 偶数秒なら成功とするダミー
if (!ok)
{
Console.WriteLine($"試行 {attempts}: 失敗");
// エラー閾値の例
if (attempts >= maxAttempts) hasError = true;
}
else
{
Console.WriteLine($"試行 {attempts}: 成功。終了します。");
isRunning = false;
}
}
Console.WriteLine($"終了状態: isRunning={isRunning}, hasError={hasError}, attempts={attempts}");
試行 1: 失敗
試行 2: 成功。終了します。
終了状態: isRunning=False, hasError=False, attempts=2
フラグは「継続条件」で考える
「続けたい」「まだ余力がある」「エラーではない」のように肯定形を基本にすると、ANDの連鎖で自然に書けます。
無限ループとエラー回避
条件が更新されないバグの典型例と原因
最頻出の原因は「条件に関わる変数が本文で更新されない」ことです。
// 典型的なバグ:i を更新していないため無限ループ
int i = 0;
while (i < 5)
{
Console.WriteLine(i);
// i++ がない!
}
- continueの分岐の中だけ更新が抜け落ちる場合も危険です。
- 浮動小数の等価判定(while (x != 1.0) など)は丸め誤差で終わらないことがあります。許容誤差で判定するか、反復回数の上限を併用します。
修正版の一例です。
int i = 0;
while (i < 5)
{
Console.WriteLine(i);
i++; // 必ず前進させる
}
0
1
2
3
4
タイムアウト・最大反復回数の設計で暴走を防ぐ
外部要因に依存するループ(ネットワーク待機、ファイル到着待ち等)では、タイムアウトや最大反復回数でフェイルセーフにします。
using System.Diagnostics;
// タイムアウトと最大反復回数を併用する例
TimeSpan timeout = TimeSpan.FromSeconds(3);
int maxLoops = 1000;
Stopwatch sw = Stopwatch.StartNew();
int loops = 0;
bool condition = true; // 仮の継続条件(外部状態により変化すると想定)
while (condition)
{
// 何らかの処理...
loops++;
// 外部状態のチェック(ここではダミーで 200回目に終了)
if (loops >= 200) condition = false;
// フェイルセーフ
if (sw.Elapsed > timeout)
{
Console.WriteLine("タイムアウトにより中断しました。");
break;
}
if (loops >= maxLoops)
{
Console.WriteLine("最大反復回数に達したため中断しました。");
break;
}
}
Console.WriteLine($"実行ループ回数: {loops}, 経過時間: {sw.Elapsed.TotalMilliseconds:F0}ms");
実行ループ回数: 200, 経過時間: 0ms
設計の指針
- 時間ベース(Stopwatch/日時)と回数ベースの二重の安全装置が堅牢です。
- ループ外に「失敗したときの扱い(再試行、エラー表示、ログ)」を必ず用意します。
whileとdo-while・forの違い
whileとdo-while(後判定)の違いと選び方
do-whileは「後判定」です。
本文を少なくとも1回は実行してから条件を判定します。
// while: 事前判定。初回から条件が偽なら一度も実行されない
int x = 10;
while (x < 0)
{
Console.WriteLine("実行されません");
}
// do-while: 後判定。本文は最低1回は実行される
int y = 10;
do
{
Console.WriteLine("これは1回だけ実行されます");
} while (y < 0);
これは1回だけ実行されます
選び方の目安は次の通りです。
初回の実行が必須(メニュー表示→選択→継続判定など)なら do-while、そうでなければ while が基本です。
whileとforの使い分け:カウンタ用途と条件駆動の比較
forは「カウンタの初期化・条件・更新」を1行にまとめられるため、単純な回数反復に適します。
whileは「いつ更新されるかが処理の中に散らばる」ような条件駆動に適します。
// 回数が決まっているなら for が簡潔
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
}
// 条件が外部要因に依存するなら while が自然
bool moreData = true;
while (moreData)
{
// データ取得
// moreData = 取得結果に応じて更新
moreData = DateTime.Now.Second % 5 != 0; // ダミー条件
}
0
1
2
3
4
5
6
7
8
9
実務での選択基準
- 反復回数が明確:for
- 条件が明確だが回数は未定:while
- 一度は必ず本文を通したい:do-while
まとめ
while文は「条件が真である間だけ処理を続ける」事前判定ループです。
ポイントは次の3つに集約されます。
第一に、条件式は比較・論理演算子を正しく組み合わせ、短絡評価を活用して安全に書くこと。
第二に、本文内で必ず状態を更新し、break/continueを適切に用いて読みやすい制御フローに整えること。
第三に、無限ループ対策としてタイムアウトや最大反復回数を設けるなどフェイルセーフを設計することです。
用途に応じてforやdo-whileと使い分けながら、ここで紹介したサンプルを出発点に、自分の要件へ当てはめていってください。