【VB.NET極意】Do…LoopとWhile…End Whileの使い分け:無限ループを回避しバグゼロを実現するループ制御の鉄則
こんにちは。チーフアーキテクトの私だ。
これまで数多の基幹システムや、現場の泥臭い業務自動化ツールを見てきたが、いまだに信じられないバグに遭遇することがある。その最たるものが「意図せぬ無限ループ」と「1回は動くべきなのに動かない幽霊ループ」だ。
VB.NETには、条件付きループを構築するための構文として `While…End While` と `Do…Loop` が存在する。
「どちらを使っても同じだろう」などと安易に考えていないか?
結論から言おう。この2つの構文の選定を誤ることは、コードの寿命を縮め、将来のバグの温床を作る自殺行為に等しい。 特にファイルストリームの読み込みやデータベースのバッチ処理において、この選択ミスは致命的なメモリリークやフリーズを引き起こす。
今回は、プロの現場で通用する「絶対に事故らないループ制御の極意」を叩き込む。
—
1. 脳裏に刻め:前置判定と後置判定の決定的な違い
ループ構文の本質は「いつ条件を評価するか」だ。
- 前置判定 (Pre-test): ループに入る前に条件を評価する。条件が不成立なら、中身は1回も実行されない。
- 後置判定 (Post-test): ループの最後に条件を評価する。条件がどうあれ、中身は最低1回は必ず実行される。
この原則を踏まえ、各構文の特性を見ていこう。
—
2. While…End While:厳格な「前置判定」の守護神
`While…End While` は、純粋な前置判定の構文だ。
.net
While 条件式
‘ 処理
End While
【特性とユースケース】
- 特徴: 条件を満たさない限り、内部のコードは1バイトたりとも実行されない。
- 最適な場面: 「処理を行う前に、前提条件が確実に満たされている必要がある場合」。
- 例:設定ファイルが存在する場合のみ読み込み処理を開始する。
- 例:残高がプラスの期間だけ計算を回す。
【危険な罠】
もしループ内で条件を変化させる変数をインクリメントし忘れたり、例外処理でループ脱出ロジックがバイパスされたりすると、即座に無限ループの完成だ。UIスレッドでこれをやらかすと、アプリは「応答なし」となり、ユーザーの怒りを買うことになる。
—
3. Do…Loop:変幻自在の万能選手(前置・後置の選択)
`Do…Loop` は、VB.NETのループ制御における真の主役である。`While` や `Until` を前置・後置のどちらにも配置できるため、表現力が圧倒的に高い。
パターンA:Do While…Loop(前置判定)
`While…End While` とほぼ同義だが、VBの伝統的な構文。
.net
Do While 条件式
‘ 処理
Loop
パターンB:Do…Loop While(後置判定)
「まずは絶対に1回実行し、その結果を見て継続を判断する」という現場で最も頻出するパターン。
.net
Do
‘ 処理(最低1回は実行される)
Loop While 条件式
—
4. 【実務の現場から】ファイルストリーム読み込みにおける鉄則
理論はこの辺りにして、実務で最も差が出る「テキストファイルの行単位読み込み(StreamReader)」を題材に、正しい設計を見せよう。
❌ やってはいけないアンチパターン(可読性の低いコード)
ファイルの終端(EOF)チェックを誤り、無限ループや予期せぬ挙動を生む典型例だ。
.net
‘ 【悪手】Whileで無理やり書いた例。読みにくい上に条件が分散しやすい。
Dim reader As New System.IO.StreamReader(“C:\data\log.txt”)
Dim line As String = reader.ReadLine()
While line IsNot Nothing
Console.WriteLine(line)
line = reader.ReadLine() ‘ 読み込み忘れや順序ミスが起きやすい
End While
reader.Close()
⭕ プロダクションコード:`Do…Loop` と `Exit Do` による堅牢な設計
ファイル読み込みやバッチ処理では、「無限ループの形をあらかじめ作り、内部で安全に離脱(Exit Do)する」のが最もバグが少なく、保守性が高い。
.net
Imports System.IO
Public Class LogProcessor
Public Sub ProcessLogFile(ByVal filePath As String)
‘ ガード節:ファイルの存在確認
If Not File.Exists(filePath) Then
Throw New FileNotFoundException(“指定されたファイルが存在しません。”, filePath)
End If
‘ Usingステートメントで確実なリソース解放(メモリリーク防止)を担保
Using reader As New StreamReader(filePath, System.Text.Encoding.UTF8)
Do
‘ 1行読み込み
Dim currentLine As String = reader.ReadLine()
‘ 【重要】EOF(ファイルの終端)に達したら即座に安全脱出
If currentLine Is Nothing Then Exit Do
‘ — ビジネスロジック(例:空行やコメント行のスキップ) —
If String.IsNullOrWhiteSpace(currentLine) OrElse currentLine.StartsWith(“#”) Then
Continue Do ‘ 次のループへスキップ
End If
‘ 実処理
ExecuteBusinessLogic(currentLine)
Loop ‘ 条件なしの無限ループに見えるが、内部の Exit Do で完全に制御されている
End Using
End Sub
Private Sub ExecuteBusinessLogic(ByVal line As String)
‘ 実際の業務処理
Console.WriteLine($”処理中: {line}”)
End Sub
End Class
このコードが優れている理由
1. Usingステートメントの活用: 例外が発生しようとも、`StreamReader` は確実に破棄(Dispose)される。リソースリークとは無縁だ。
2. 制御の局所化: 「無限 `Do…Loop` + 内部の `Exit Do`」の構造にすることで、ループの継続条件が複雑化した際にもスパゲッティコードになりにくい。
3. `Continue Do` の適切な利用: 処理対象外のデータをエレガントにスキップし、インデントの深化(Arrow Anti-pattern)を防いでいる。
—
5. 選択の基準まとめ(チーフアーキテクトからの提言)
どの構文を使うべきか迷ったときは、以下のマトリクスを思い出してほしい。
| 状況・要件 | 推奨する構文 | 理由 |
| :— | :— | :— |
| ループ内の処理を「絶対に1回は実行したい」 | `Do…Loop While` (後置) | 最初の1回を実行してから判定するため、初期化の手間がいらない。 |
| ループ開始前に条件を満たさない可能性がある | `While…End While` または `Do While…Loop` (前置) | 無駄な処理の実行を防ぐ。 |
| ファイル読み込みやDBのレコードフェッチ | `Do…Loop` + `Exit Do` | 終了条件が複雑になりがちなストリーム処理において、最も安全かつ明確に離脱できる。 |
最後に
コードの美しさは、そのまま保守性の高さに直結する。
「動けばいいや」で作られた場当たり的なループは、やがてシステム改修の際に開発者の足をすくい、深刻な障害を引き起こす。
今回伝授した「条件評価のタイミングの理解」と「安全な脱出制御」をマスターすれば、あなたの書くVB.NETコードは一段も二段も洗練された、プロフェッショナルな代物に生まれ変わるはずだ。
現場の信頼を勝ち取る堅牢なコードを、明日からの開発に役立ててほしい。
