コレクション処理と foreach ループ
C#プログラミングでは、List<T>や配列(string[]など)といった「コレクション」に格納された複数のデータを、先頭から順に一つずつ取り出して処理する場面が非常に多くあります。
forループを使用してインデックス(i)を管理しながら list[i] のようにアクセスすることも可能ですが、インデックスの管理は煩雑で、範囲外エラー(IndexOutOfRangeException)の原因にもなり得ます。
このようなコレクションの全要素に対する繰り返し処理を、より安全かつ直感的に記述するために用意されているのが foreach ループです。
foreach の基本構文
foreachループは、コレクションが保持している要素の数だけ自動的に繰り返し処理を行い、現在の要素を変数に格納してブロック内で使用できるようにします。
foreach (var [一時変数名] in [コレクション])
{
// コレクション内の各要素(一時変数)を使った処理
}
var [一時変数名]: コレクションから取り出された「現在の要素」を格納する変数です。varを使用すると、型(int、stringなど)が自動的に推論されます。in [コレクション]: 処理対象となる配列やList<T>などのコレクションを指定します。
forループと異なり、カウンター変数(i)の初期化や増減、CountやLengthを使った条件比較を記述する必要が一切ありません。
foreach のコード例
例1: 文字列リストの処理
List<string>に格納された複数のファイル名を、一つずつコンソールに出力する例です。
using System;
using System.Collections.Generic;
public class ForeachStringExample
{
public static void Main()
{
// 処理対象のファイル名リスト
var fileNames = new List<string> { "document.pdf", "image.png", "data.csv" };
Console.WriteLine("--- 処理対象ファイル一覧 ---");
// foreach ループでリストの全要素を処理
foreach (var name in fileNames)
{
// 'name' 変数には "document.pdf", "image.png"... が順番に格納される
Console.WriteLine($"ファイル名: {name}");
}
}
}
出力結果:
--- 処理対象ファイル一覧 ---
ファイル名: document.pdf
ファイル名: image.png
ファイル名: data.csv
例2: 数値配列の合計
配列(decimal[])に格納された商品価格の合計を計算する例です。
using System;
public class ForeachSumExample
{
public static void Main()
{
// 商品価格の配列
var itemPrices = new decimal[] { 1500m, 280.5m, 3000m };
decimal totalAmount = 0m;
// foreach ループで配列の全要素にアクセス
foreach (var price in itemPrices)
{
// 'price' 変数に 1500m, 280.5m... が順番に格納される
totalAmount += price;
}
Console.WriteLine($"合計金額: {totalAmount:C}"); // C: 通貨形式で表示
}
}
出力結果:
合計金額: ¥4,780.5
foreach の重要な注意点
foreachは非常に便利ですが、使用時には守るべき重要なルールが2つあります。
1. ループ変数は読み取り専用
foreachブロック内で使用される一時変数(上記の例では name や price)は**読み取り専用(Read-only)**です。
この変数に新しい値を代入しようとすると、コンパイルエラーが発生します。
foreach (var price in itemPrices)
{
// price = price * 1.1m; // これはコンパイルエラーになる
}
2. ループ実行中のコレクション変更は禁止
foreachでコレクションを処理している最中に、そのコレクションの要素を追加(Add)したり、削除(Remove)したりすることはできません。
もし実行した場合、プログラムはInvalidOperationExceptionという実行時エラーをスローして停止します。
var users = new List<string> { "userA", "userB_guest", "userC" };
// 実行時エラーになる悪い例
foreach (var user in users)
{
if (user.Contains("_guest"))
{
// users.Remove(user); // InvalidOperationException が発生する!
}
}
もし、ループ中にコレクションの要素を削除したい場合は、foreachではなく、インデックスを逆順(i--)に処理するforループなど、別の方法を検討する必要があります。
まとめ
foreachループは、C#において配列やリストなどのコレクションに含まれる全ての要素に対して、順番に処理を行うための最も安全で可読性の高い構文です。
インデックス管理の必要がなく、コードが簡潔になる一方で、「ループ変数は読み取り専用」であり、「ループ中にコレクション自体を変更してはならない」というルールを理解して使用することが重要です。
