C# foreachの使い方を初心者向けに解説|配列・List・Dictionaryの基本から注意点まで
はじめに
C#で配列やList、Dictionaryなどのデータを順番に処理したいときによく使うのがforeach文です。
foreachは、コレクションの中にある要素を1つずつ取り出して処理するための繰り返し構文です。たとえば、名前の一覧を順番に表示したり、数値のリストを合計したり、Dictionaryのキーと値を一覧表示したりするときに使います。
C#初心者のうちは、for文とforeach文の違いが分かりにくいかもしれません。しかし、foreachは書き方がシンプルで読みやすいため、配列やListの全要素を処理する場面では特に便利です。
この記事では、C#のforeachの基本構文から、配列・List・Dictionaryでの使い方、breakやcontinueとの組み合わせ、初心者がつまずきやすい注意点まで解説します。
1. C#のforeachとは?配列やListの要素を順番に取り出す繰り返し処理
C#のforeachは、配列やListなどのコレクションに含まれる要素を、先頭から順番に取り出して処理するための構文です。
たとえば、次のような文字列の配列があるとします。
C#string[] names = { "田中", "佐藤", "鈴木" };
この配列の要素を1つずつ表示したい場合、foreachを使うと次のように書けます。
C#foreach (string name in names)
{
Console.WriteLine(name);
}
実行結果は次のようになります。
C#田中
佐藤
鈴木
foreachを使うと、「コレクションの中身を順番に取り出して処理する」という目的が分かりやすいコードになります。
1-1. foreach文の役割と初心者が使う場面
foreach文の役割は、コレクションの要素を1つずつ取り出して、同じ処理を繰り返すことです。
初心者がよく使う場面には、次のようなものがあります。
C#string[] fruits = { "りんご", "みかん", "バナナ" };
foreach (string fruit in fruits)
{
Console.WriteLine(fruit);
}
このコードでは、fruits配列の中から要素を1つずつ取り出し、fruitという変数に入れて表示しています。
foreachは、次のような処理に向いています。
配列の全要素を表示する処理。
C#int[] numbers = { 10, 20, 30 };
foreach (int number in numbers)
{
Console.WriteLine(number);
}
Listの中身を順番に確認する処理。
C#List<string> names = new List<string> { "田中", "佐藤", "鈴木" };
foreach (string name in names)
{
Console.WriteLine(name);
}
Dictionaryのキーと値を取り出す処理。
C#Dictionary<string, int> scores = new Dictionary<string, int>
{
{ "田中", 80 },
{ "佐藤", 90 },
{ "鈴木", 75 }
};
foreach (var score in scores)
{
Console.WriteLine($"{score.Key}: {score.Value}");
}
このように、foreachは「データの一覧を順番に処理したい」ときに使いやすい構文です。
1-2. foreachでできること・できないこと
foreachでできる代表的なことは、コレクションの要素を順番に取り出して処理することです。
たとえば、要素を表示できます。
C#int[] numbers = { 1, 2, 3 };
foreach (int number in numbers)
{
Console.WriteLine(number);
}
条件に合う要素だけを処理することもできます。
C#int[] numbers = { 1, 2, 3, 4, 5 };
foreach (int number in numbers)
{
if (number % 2 == 0)
{
Console.WriteLine(number);
}
}
合計を求めることもできます。
C#int[] numbers = { 10, 20, 30 };
int total = 0;
foreach (int number in numbers)
{
total += number;
}
Console.WriteLine(total);
一方で、foreachには苦手なこともあります。
たとえば、現在のインデックス番号をそのまま使いたい場合は、foreachよりもfor文の方が向いています。
C#string[] names = { "田中", "佐藤", "鈴木" };
for (int i = 0; i < names.Length; i++)
{
Console.WriteLine($"{i}: {names[i]}");
}
また、foreachでListを回している最中に、そのListへ要素を追加したり削除したりするとエラーになることがあります。
C#List<string> names = new List<string> { "田中", "佐藤", "鈴木" };
foreach (string name in names)
{
if (name == "佐藤")
{
names.Remove(name); // エラーの原因になる
}
}
foreachは、基本的には「中身を読み取って処理する」用途に向いています。
1-3. for文やwhile文との違い
C#には、foreach以外にもfor文やwhile文があります。
for文は、回数やインデックスを使って繰り返し処理をしたいときに便利です。
C#string[] names = { "田中", "佐藤", "鈴木" };
for (int i = 0; i < names.Length; i++)
{
Console.WriteLine(names[i]);
}
このコードでは、iというインデックス番号を使って配列の要素にアクセスしています。
一方、foreachではインデックス番号を意識せずに要素を取り出せます。
C#string[] names = { "田中", "佐藤", "鈴木" };
foreach (string name in names)
{
Console.WriteLine(name);
}
while文は、条件が成り立っている間だけ処理を繰り返す構文です。
C#int count = 0;
while (count < 3)
{
Console.WriteLine(count);
count++;
}
while文は、繰り返し回数が事前に決まっていない場合によく使われます。
それぞれの違いを簡単にまとめると、foreachはコレクションの全要素を順番に処理したいとき、for文はインデックスや回数を管理したいとき、while文は条件を満たす間だけ繰り返したいときに使います。
1-4. foreachが読みやすいコードを書きやすい理由
foreachが読みやすい理由は、コードの目的がはっきり分かるからです。
たとえば、次のfor文を見てみましょう。
C#string[] names = { "田中", "佐藤", "鈴木" };
for (int i = 0; i < names.Length; i++)
{
Console.WriteLine(names[i]);
}
このコードは問題なく動きますが、iやnames.Length、names[i]など、インデックスに関する記述が必要です。
同じ処理をforeachで書くと、次のようになります。
C#foreach (string name in names)
{
Console.WriteLine(name);
}
こちらの方が、「namesの中からnameを1つずつ取り出して表示する」という流れが直感的に分かります。
初心者にとっては、余計なインデックス管理をしなくてよい点が大きなメリットです。インデックスの開始位置や終了条件を間違える心配も少なくなります。
2. C# foreachの基本構文と書き方
C#のforeach文は、基本構文を覚えればすぐに使えます。
配列、List、Dictionaryなど、複数のデータを持つコレクションに対して使うことができます。
2-1. foreach文の基本形
foreach文の基本形は次の通りです。
C#foreach (型 変数名 in コレクション)
{
繰り返したい処理;
}
具体例を見てみましょう。
C#string[] fruits = { "りんご", "みかん", "バナナ" };
foreach (string fruit in fruits)
{
Console.WriteLine(fruit);
}
このコードでは、fruits配列の要素が1つずつfruitに入り、Console.WriteLineで表示されます。
実行結果は次の通りです。
C#りんご
みかん
バナナ
2-2. 変数・in・コレクションの意味
foreach文の中にあるそれぞれの要素の意味を確認しましょう。
C#foreach (string fruit in fruits)
{
Console.WriteLine(fruit);
}
stringは、取り出す要素の型です。この例では、fruits配列の中身が文字列なのでstringと書いています。
fruitは、取り出した1つの要素を入れる変数です。ループが1回進むごとに、次の要素がfruitに入ります。
inは、「このコレクションの中から取り出す」という意味で使われます。
fruitsは、繰り返し処理の対象になるコレクションです。
つまり、次のコードは「fruitsの中からfruitを1つずつ取り出して処理する」という意味になります。
C#foreach (string fruit in fruits)
{
Console.WriteLine(fruit);
}
2-3. varを使う書き方と型を明示する書き方
foreachでは、型を明示して書くことも、varを使って書くこともできます。
型を明示する場合は、次のように書きます。
C#List<int> numbers = new List<int> { 10, 20, 30 };
foreach (int number in numbers)
{
Console.WriteLine(number);
}
varを使う場合は、次のように書けます。
C#List<int> numbers = new List<int> { 10, 20, 30 };
foreach (var number in numbers)
{
Console.WriteLine(number);
}
この場合、numberの型はC#が自動的にintだと判断します。
varを使うとコードを短く書けますが、初心者のうちは型を明示した方が理解しやすい場合もあります。
Dictionaryのように型名が長くなる場合は、varを使うと読みやすくなります。
C#Dictionary<string, int> scores = new Dictionary<string, int>
{
{ "田中", 80 },
{ "佐藤", 90 }
};
foreach (var score in scores)
{
Console.WriteLine($"{score.Key}: {score.Value}");
}
この例では、scoreにはDictionaryの1要素が入ります。score.Keyでキー、score.Valueで値を取得できます。
2-4. foreach内で複数行の処理を書く方法
foreachの中には、複数行の処理を書くことができます。
C#string[] names = { "田中", "佐藤", "鈴木" };
foreach (string name in names)
{
Console.WriteLine("名前を表示します");
Console.WriteLine(name);
Console.WriteLine("-----");
}
実行結果は次のようになります。
C#名前を表示します
田中
-----
名前を表示します
佐藤
-----
名前を表示します
鈴木
-----
foreachの中では、通常のC#コードと同じように、変数の宣言、if文、計算、メソッド呼び出しなどを書くことができます。
C#int[] numbers = { 1, 2, 3, 4, 5 };
foreach (int number in numbers)
{
int doubled = number * 2;
Console.WriteLine($"{number}の2倍は{doubled}です");
}
2-5. foreachで使える主なコレクション
foreachは、さまざまなコレクションに使えます。
代表的なものは次の通りです。
配列。
C#int[] numbers = { 1, 2, 3 };
foreach (int number in numbers)
{
Console.WriteLine(number);
}
List。
C#List<string> names = new List<string> { "田中", "佐藤" };
foreach (string name in names)
{
Console.WriteLine(name);
}
Dictionary。
C#Dictionary<string, int> scores = new Dictionary<string, int>
{
{ "田中", 80 },
{ "佐藤", 90 }
};
foreach (var score in scores)
{
Console.WriteLine($"{score.Key}: {score.Value}");
}
HashSet。
C#HashSet<string> tags = new HashSet<string> { "C#", "foreach", "List" };
foreach (string tag in tags)
{
Console.WriteLine(tag);
}
文字列。
C#string text = "CSharp";
foreach (char c in text)
{
Console.WriteLine(c);
}
foreachは、正確には「列挙できるオブジェクト」に対して使えます。初心者のうちは、配列、List、Dictionaryでよく使うと覚えておくとよいでしょう。
3. 配列をforeachで処理する方法
配列は、同じ型のデータをまとめて扱うための基本的なデータ構造です。
foreachを使うと、配列の要素を簡単に順番に処理できます。
3-1. 文字列配列を順番に表示するサンプル
文字列配列をforeachで表示する例です。
C#string[] fruits = { "りんご", "みかん", "バナナ" };
foreach (string fruit in fruits)
{
Console.WriteLine(fruit);
}
実行結果は次の通りです。
C#りんご
みかん
バナナ
配列の要素が1つずつfruitに入り、ループの中で表示されます。
for文で同じ処理を書くと次のようになります。
C#string[] fruits = { "りんご", "みかん", "バナナ" };
for (int i = 0; i < fruits.Length; i++)
{
Console.WriteLine(fruits[i]);
}
foreachの方が、インデックスを使わない分だけシンプルに書けます。
3-2. 数値配列の合計を求めるサンプル
foreachは、配列の値を使って計算する場合にも便利です。
次の例では、数値配列の合計を求めています。
C#int[] numbers = { 10, 20, 30, 40 };
int total = 0;
foreach (int number in numbers)
{
total += number;
}
Console.WriteLine($"合計: {total}");
実行結果は次の通りです。
C#合計: 100
total += number;は、totalにnumberを加算する処理です。
ループが進むたびに、配列の値が順番に足されていきます。
3-3. 配列の要素数が変わっても対応しやすい理由
foreachを使うと、配列の要素数を意識しなくても全要素を処理できます。
たとえば、次のように要素が3つの配列があるとします。
C#string[] names = { "田中", "佐藤", "鈴木" };
foreach (string name in names)
{
Console.WriteLine(name);
}
あとから要素を増やしても、foreachのコードを変更する必要はありません。
C#string[] names = { "田中", "佐藤", "鈴木", "高橋", "伊藤" };
foreach (string name in names)
{
Console.WriteLine(name);
}
foreachは自動的に配列の最後まで処理してくれます。
for文でもnames.Lengthを使えば対応できますが、foreachの方が「全要素を処理する」という意図がより明確です。
3-4. 配列でforeachを使うときの注意点
配列をforeachで処理するときは、ループ変数に値を代入しても、配列の要素そのものを変更できない点に注意が必要です。
たとえば、次のコードはコンパイルエラーになります。
C#int[] numbers = { 1, 2, 3 };
foreach (int number in numbers)
{
number = number * 2; // エラー
}
foreachのループ変数は読み取り用として扱われるため、直接代入できません。
配列の要素を変更したい場合は、for文を使うのが一般的です。
C#int[] numbers = { 1, 2, 3 };
for (int i = 0; i < numbers.Length; i++)
{
numbers[i] = numbers[i] * 2;
}
foreach (int number in numbers)
{
Console.WriteLine(number);
}
実行結果は次の通りです。
C#2
4
6
配列の中身を読み取るだけならforeach、要素そのものを書き換えるならfor文、と考えると分かりやすいです。
4. Listをforeachで処理する方法
List<T>は、C#でよく使われるコレクションです。
配列と似ていますが、要素の追加や削除がしやすいという特徴があります。foreachを使えば、Listの要素も簡単に順番に処理できます。
4-1. Listの要素を順番に取り出す基本例
Listの要素をforeachで表示する基本例です。
C#List<string> names = new List<string> { "田中", "佐藤", "鈴木" };
foreach (string name in names)
{
Console.WriteLine(name);
}
実行結果は次の通りです。
C#田中
佐藤
鈴木
Listでも配列と同じように、要素が1つずつループ変数に入ります。
varを使って次のように書くこともできます。
C#List<string> names = new List<string> { "田中", "佐藤", "鈴木" };
foreach (var name in names)
{
Console.WriteLine(name);
}
4-2. Listの中から条件に合う要素を表示する例
foreachは、if文と組み合わせて条件に合う要素だけを処理できます。
次の例では、80点以上の点数だけを表示しています。
C#List<int> scores = new List<int> { 65, 80, 92, 70, 88 };
foreach (int score in scores)
{
if (score >= 80)
{
Console.WriteLine(score);
}
}
実行結果は次の通りです。
C#80
92
88
文字列のListでも同じように使えます。
C#List<string> names = new List<string> { "Tanaka", "Sato", "Suzuki", "Takahashi" };
foreach (string name in names)
{
if (name.StartsWith("S"))
{
Console.WriteLine(name);
}
}
実行結果は次の通りです。
C#Sato
Suzuki
4-3. Listの要素を集計する例
Listの数値を集計する例です。
C#List<int> prices = new List<int> { 100, 200, 150, 300 };
int total = 0;
foreach (int price in prices)
{
total += price;
}
Console.WriteLine($"合計金額: {total}");
実行結果は次の通りです。
C#合計金額: 750
件数を数えることもできます。
C#List<int> scores = new List<int> { 65, 80, 92, 70, 88 };
int count = 0;
foreach (int score in scores)
{
if (score >= 80)
{
count++;
}
}
Console.WriteLine($"80点以上の人数: {count}");
実行結果は次の通りです。
C#80点以上の人数: 3
このように、foreachはListの中身を確認しながら集計する処理にも向いています。
4-4. List.ForEachメソッドとの違い
Listには、foreach文とは別にForEachメソッドがあります。
C#List<string> names = new List<string> { "田中", "佐藤", "鈴木" };
names.ForEach(name =>
{
Console.WriteLine(name);
});
このコードも、Listの要素を順番に処理します。
一方、通常のforeach文では次のように書きます。
C#foreach (string name in names)
{
Console.WriteLine(name);
}
初心者には、通常のforeach文の方が分かりやすいです。
List.ForEachはラムダ式を使うため、C#に慣れていない段階では少し読みにくく感じるかもしれません。
また、breakやcontinueのような制御文は、通常のforeach文の方が自然に使えます。
C#foreach (string name in names)
{
if (name == "佐藤")
{
break;
}
Console.WriteLine(name);
}
基本的には、初心者のうちはforeach文を優先して覚えるとよいでしょう。
4-5. Listでforeachを使うときに避けたい書き方
Listをforeachで処理している最中に、そのListの要素を追加・削除する書き方は避けましょう。
たとえば、次のコードはエラーの原因になります。
C#List<string> names = new List<string> { "田中", "佐藤", "鈴木" };
foreach (string name in names)
{
if (name == "佐藤")
{
names.Remove(name); // エラーの原因
}
}
このような場合は、削除対象を別のListに集めてから削除する方法があります。
C#List<string> names = new List<string> { "田中", "佐藤", "鈴木" };
List<string> removeNames = new List<string>();
foreach (string name in names)
{
if (name == "佐藤")
{
removeNames.Add(name);
}
}
foreach (string name in removeNames)
{
names.Remove(name);
}
または、RemoveAllを使う方法もあります。
C#List<string> names = new List<string> { "田中", "佐藤", "鈴木" };
names.RemoveAll(name => name == "佐藤");
foreach中は、対象のListを変更しないのが基本です。
5. Dictionaryをforeachで処理する方法
Dictionary<TKey, TValue>は、キーと値のペアでデータを管理するコレクションです。
たとえば、名前をキー、点数を値として管理できます。
C#Dictionary<string, int> scores = new Dictionary<string, int>
{
{ "田中", 80 },
{ "佐藤", 90 },
{ "鈴木", 75 }
};
foreachを使うと、Dictionaryのキーと値を順番に取り出せます。
5-1. Dictionaryのキーと値を取り出す基本例
Dictionaryをforeachで処理する基本例です。
C#Dictionary<string, int> scores = new Dictionary<string, int>
{
{ "田中", 80 },
{ "佐藤", 90 },
{ "鈴木", 75 }
};
foreach (var score in scores)
{
Console.WriteLine($"{score.Key}: {score.Value}");
}
実行結果の例は次の通りです。
C#田中: 80
佐藤: 90
鈴木: 75
score.Keyでキーを取得し、score.Valueで値を取得します。
5-2. KeyValuePairを使った書き方
Dictionaryの1要素は、KeyValuePair<TKey, TValue>として扱えます。
型を明示して書くと、次のようになります。
C#Dictionary<string, int> scores = new Dictionary<string, int>
{
{ "田中", 80 },
{ "佐藤", 90 },
{ "鈴木", 75 }
};
foreach (KeyValuePair<string, int> score in scores)
{
Console.WriteLine($"{score.Key}: {score.Value}");
}
KeyValuePair<string, int>は、「string型のキー」と「int型の値」を持つペアという意味です。
ただし、型名が長くなるため、実際のコードではvarを使うことも多いです。
C#foreach (var score in scores)
{
Console.WriteLine($"{score.Key}: {score.Value}");
}
初心者のうちは、最初にKeyValuePairの意味を理解し、その後はvarを使うと読みやすくなります。
5-3. Keysだけをforeachで回す方法
Dictionaryのキーだけを処理したい場合は、Keysを使います。
C#Dictionary<string, int> scores = new Dictionary<string, int>
{
{ "田中", 80 },
{ "佐藤", 90 },
{ "鈴木", 75 }
};
foreach (string name in scores.Keys)
{
Console.WriteLine(name);
}
実行結果の例は次の通りです。
C#田中
佐藤
鈴木
キーを使って値を取り出すこともできます。
C#foreach (string name in scores.Keys)
{
Console.WriteLine($"{name}: {scores[name]}");
}
ただし、キーと値の両方を使いたい場合は、Dictionary本体をforeachで回してKeyとValueを使う方が分かりやすいです。
C#foreach (var score in scores)
{
Console.WriteLine($"{score.Key}: {score.Value}");
}
5-4. Valuesだけをforeachで回す方法
Dictionaryの値だけを処理したい場合は、Valuesを使います。
C#Dictionary<string, int> scores = new Dictionary<string, int>
{
{ "田中", 80 },
{ "佐藤", 90 },
{ "鈴木", 75 }
};
foreach (int score in scores.Values)
{
Console.WriteLine(score);
}
実行結果の例は次の通りです。
C#80
90
75
値の合計を求めることもできます。
C#int total = 0;
foreach (int score in scores.Values)
{
total += score;
}
Console.WriteLine($"合計点: {total}");
実行結果は次の通りです。
C#合計点: 245
キーが不要で、値だけを処理したい場合はValuesを使うとシンプルです。
5-5. Dictionaryのforeachで順番に依存してはいけない理由
Dictionaryをforeachで処理するときは、順番に依存しないようにしましょう。
Dictionaryは、キーと値の対応を管理するためのコレクションです。Listや配列のように、「1番目」「2番目」という順番を主目的とするコレクションではありません。
そのため、次のようなコードで表示順を前提にするのは避けた方が安全です。
C#foreach (var score in scores)
{
Console.WriteLine($"{score.Key}: {score.Value}");
}
実行環境によっては追加した順番で表示されることもありますが、Dictionaryを使うときは「順番が必要な処理には向かない」と考えるのが基本です。
順番が必要な場合は、Listを使う、またはLINQのOrderByなどで並び替えてから処理します。
C#foreach (var score in scores.OrderBy(x => x.Key))
{
Console.WriteLine($"{score.Key}: {score.Value}");
}
この例では、キーの昇順で並び替えてから表示しています。
6. foreachでよく使う制御文
foreachの中では、break、continue、if文などの制御文を使えます。
これらを組み合わせることで、条件に応じて処理を中断したり、特定の要素をスキップしたりできます。
6-1. breakでループを途中終了する方法
breakを使うと、foreachの処理を途中で終了できます。
次の例では、Listの中から「佐藤」を見つけた時点でループを終了します。
C#List<string> names = new List<string> { "田中", "佐藤", "鈴木", "高橋" };
foreach (string name in names)
{
if (name == "佐藤")
{
Console.WriteLine("佐藤さんが見つかりました");
break;
}
Console.WriteLine(name);
}
実行結果は次の通りです。
C#田中
佐藤さんが見つかりました
breakが実行されると、それ以降の要素は処理されません。
検索処理で目的のデータが見つかったときなどに便利です。
6-2. continueで次の処理に進む方法
continueを使うと、現在のループ処理をスキップして、次の要素へ進めます。
次の例では、偶数だけを表示しています。
C#int[] numbers = { 1, 2, 3, 4, 5 };
foreach (int number in numbers)
{
if (number % 2 != 0)
{
continue;
}
Console.WriteLine(number);
}
実行結果は次の通りです。
C#2
4
奇数の場合はcontinueが実行され、Console.WriteLineまで進まずに次の要素へ移ります。
条件に合わないデータをスキップしたいときに使えます。
6-3. if文と組み合わせて条件分岐する方法
foreachは、if文と組み合わせて使うことが非常に多いです。
次の例では、点数によって表示内容を変えています。
C#List<int> scores = new List<int> { 95, 70, 45, 80 };
foreach (int score in scores)
{
if (score >= 80)
{
Console.WriteLine($"{score}点: 合格");
}
else
{
Console.WriteLine($"{score}点: 再テスト");
}
}
実行結果は次の通りです。
C#95点: 合格
70点: 再テスト
45点: 再テスト
80点: 合格
条件が複数ある場合は、else ifも使えます。
C#foreach (int score in scores)
{
if (score >= 90)
{
Console.WriteLine("評価A");
}
else if (score >= 70)
{
Console.WriteLine("評価B");
}
else
{
Console.WriteLine("評価C");
}
}
6-4. ネストしたforeachの書き方
foreachの中に、さらにforeachを書くこともできます。これをネストしたforeachと呼びます。
たとえば、2次元的なデータを処理するときに使います。
C#List<List<string>> groups = new List<List<string>>
{
new List<string> { "田中", "佐藤" },
new List<string> { "鈴木", "高橋" }
};
foreach (List<string> group in groups)
{
foreach (string name in group)
{
Console.WriteLine(name);
}
}
実行結果は次の通りです。
C#田中
佐藤
鈴木
高橋
外側のforeachでグループを取り出し、内側のforeachでグループ内の名前を取り出しています。
ただし、ネストが深くなるとコードが読みにくくなります。必要以上にforeachを入れ子にしすぎないようにしましょう。
6-5. foreach内で例外処理を使う場合の考え方
foreachの中でエラーが起きる可能性がある処理を行う場合、try-catchを使って例外処理を書くことがあります。
たとえば、文字列を数値に変換する処理です。
C#List<string> values = new List<string> { "10", "20", "abc", "30" };
foreach (string value in values)
{
try
{
int number = int.Parse(value);
Console.WriteLine(number);
}
catch (FormatException)
{
Console.WriteLine($"{value}は数値に変換できません");
}
}
実行結果は次の通りです。
C#10
20
abcは数値に変換できません
30
ただし、変換できるかどうかを確認するだけなら、int.TryParseを使う方がよく使われます。
C#foreach (string value in values)
{
if (int.TryParse(value, out int number))
{
Console.WriteLine(number);
}
else
{
Console.WriteLine($"{value}は数値ではありません");
}
}
foreach内で例外処理を書く場合は、「本当に例外処理が必要か」「事前に判定できないか」を考えるとよいでしょう。
7. foreachで初心者がつまずきやすい注意点
foreachは便利ですが、初心者がつまずきやすいポイントもあります。
特に、ループ中の追加・削除、値の変更、null、インデックスの扱いには注意が必要です。
7-1. foreach中にコレクションを追加・削除するとエラーになる
foreachでコレクションを回している最中に、そのコレクションへ要素を追加・削除すると、エラーになることがあります。
C#List<string> names = new List<string> { "田中", "佐藤", "鈴木" };
foreach (string name in names)
{
if (name == "佐藤")
{
names.Remove(name); // エラーの原因
}
}
このような場合、実行時に次のようなエラーが発生することがあります。
C#InvalidOperationException: Collection was modified; enumeration operation may not execute.
対処法としては、削除対象を別に集めてから削除する方法があります。
C#List<string> names = new List<string> { "田中", "佐藤", "鈴木" };
List<string> removeNames = new List<string>();
foreach (string name in names)
{
if (name == "佐藤")
{
removeNames.Add(name);
}
}
foreach (string name in removeNames)
{
names.Remove(name);
}
また、条件に合う要素をまとめて削除するならRemoveAllも便利です。
C#names.RemoveAll(name => name == "佐藤");
7-2. 要素の値を直接変更できないケースがある
foreachのループ変数には、直接値を代入できません。
C#int[] numbers = { 1, 2, 3 };
foreach (int number in numbers)
{
number = number * 2; // エラー
}
要素の値を変更したい場合は、for文を使ってインデックスでアクセスします。
C#int[] numbers = { 1, 2, 3 };
for (int i = 0; i < numbers.Length; i++)
{
numbers[i] = numbers[i] * 2;
}
ただし、オブジェクトのプロパティを変更する場合は、foreach内でも変更できることがあります。
C#class User
{
public string Name { get; set; }
public int Age { get; set; }
}
List<User> users = new List<User>
{
new User { Name = "田中", Age = 20 },
new User { Name = "佐藤", Age = 25 }
};
foreach (User user in users)
{
user.Age += 1;
}
この例では、user変数そのものに別の値を代入しているのではなく、参照先のオブジェクトのAgeプロパティを変更しています。
7-3. インデックス番号が必要な場合はfor文も検討する
foreachは要素を順番に取り出すのが得意ですが、インデックス番号を直接扱う構文ではありません。
たとえば、次のように番号付きで表示したい場合は、for文が分かりやすいです。
C#string[] names = { "田中", "佐藤", "鈴木" };
for (int i = 0; i < names.Length; i++)
{
Console.WriteLine($"{i}: {names[i]}");
}
foreachでもカウンター用の変数を用意すれば実現できます。
C#string[] names = { "田中", "佐藤", "鈴木" };
int index = 0;
foreach (string name in names)
{
Console.WriteLine($"{index}: {name}");
index++;
}
ただし、インデックスを多く使う処理では、無理にforeachを使わずfor文を検討しましょう。
7-4. nullのコレクションにforeachを使うとエラーになる
foreachの対象がnullの場合、エラーになります。
C#List<string> names = null;
foreach (string name in names)
{
Console.WriteLine(name);
}
このコードは、NullReferenceExceptionの原因になります。
事前にnullチェックを行いましょう。
C#List<string> names = null;
if (names != null)
{
foreach (string name in names)
{
Console.WriteLine(name);
}
}
また、空のListを使うようにすると、foreachで安全に処理できます。
C#List<string> names = new List<string>();
foreach (string name in names)
{
Console.WriteLine(name);
}
空のListであれば、ループ内の処理は実行されませんが、エラーにはなりません。
7-5. ループ変数のスコープを理解する
foreachで宣言したループ変数は、foreachのブロック内で使えます。
C#string[] names = { "田中", "佐藤" };
foreach (string name in names)
{
Console.WriteLine(name);
}
// Console.WriteLine(name); // ここでは使えない
nameはforeachの中で宣言されているため、ループの外では使えません。
ループの外でも値を使いたい場合は、外側で変数を用意します。
C#string[] names = { "田中", "佐藤" };
string lastName = "";
foreach (string name in names)
{
lastName = name;
}
Console.WriteLine($"最後の名前: {lastName}");
変数がどこで使えるかを意識すると、スコープに関するエラーを減らせます。
8. foreachとfor文の使い分け
foreachとfor文はどちらも繰り返し処理に使いますが、得意な場面が異なります。
全要素を順番に処理するならforeach、インデックスを使って細かく制御するならfor文が向いています。
8-1. foreachを使うべきケース
foreachを使うべきなのは、コレクションの要素を最初から最後まで順番に処理したい場合です。
C#List<string> names = new List<string> { "田中", "佐藤", "鈴木" };
foreach (string name in names)
{
Console.WriteLine(name);
}
次のような処理では、foreachが読みやすくなります。
全要素を表示する処理。
C#foreach (string name in names)
{
Console.WriteLine(name);
}
条件に合う要素だけを表示する処理。
C#foreach (string name in names)
{
if (name.StartsWith("佐"))
{
Console.WriteLine(name);
}
}
合計や件数を求める処理。
C#List<int> scores = new List<int> { 80, 90, 75 };
int total = 0;
foreach (int score in scores)
{
total += score;
}
インデックスが不要な処理では、foreachを使うとコードがすっきりします。
8-2. for文を使うべきケース
for文を使うべきなのは、インデックス番号が必要な場合です。
C#string[] names = { "田中", "佐藤", "鈴木" };
for (int i = 0; i < names.Length; i++)
{
Console.WriteLine($"{i}: {names[i]}");
}
また、配列やListの要素を直接変更したい場合も、for文が向いています。
C#int[] numbers = { 1, 2, 3 };
for (int i = 0; i < numbers.Length; i++)
{
numbers[i] *= 2;
}
逆順に処理したい場合も、for文が分かりやすいです。
C#string[] names = { "田中", "佐藤", "鈴木" };
for (int i = names.Length - 1; i >= 0; i--)
{
Console.WriteLine(names[i]);
}
このように、順番や位置を細かく制御したい場合はfor文を使いましょう。
8-3. インデックスが必要な処理の書き方
foreachでインデックスが必要な場合は、カウンター変数を用意します。
C#List<string> names = new List<string> { "田中", "佐藤", "鈴木" };
int index = 0;
foreach (string name in names)
{
Console.WriteLine($"{index}: {name}");
index++;
}
実行結果は次の通りです。
C#0: 田中
1: 佐藤
2: 鈴木
ただし、インデックスを使うことが処理の中心になるなら、for文の方が自然です。
C#for (int i = 0; i < names.Count; i++)
{
Console.WriteLine($"{i}: {names[i]}");
}
C#では、LINQのSelectを使ってインデックス付きで処理する方法もあります。
C#foreach (var item in names.Select((name, index) => new { name, index }))
{
Console.WriteLine($"{item.index}: {item.name}");
}
ただし、初心者のうちは、無理に複雑な書き方をせず、for文を使う方が分かりやすいです。
8-4. パフォーマンスを気にする場面での考え方
通常のアプリケーション開発では、foreachとfor文の速度差を過度に気にする必要はありません。
ほとんどの場合、読みやすさを優先して問題ありません。
C#foreach (int number in numbers)
{
Console.WriteLine(number);
}
ただし、大量のデータを何度も処理する場合や、ゲーム、リアルタイム処理、高速化が必要な処理では、パフォーマンスを意識することがあります。
その場合は、実際に処理時間を測定して判断することが大切です。
C#var watch = System.Diagnostics.Stopwatch.StartNew();
// 測定したい処理
foreach (int number in numbers)
{
int result = number * 2;
}
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds);
最初から速度だけを理由にforeachを避ける必要はありません。まずは読みやすく正しいコードを書き、必要になったら測定して改善するのが基本です。
8-5. 初心者はどちらを優先して覚えるべきか
初心者は、foreachとfor文の両方を覚えるのがおすすめです。
ただし、配列やListの全要素を処理する場面では、まずforeachを優先して使うとよいでしょう。
C#foreach (string name in names)
{
Console.WriteLine(name);
}
foreachは、インデックス管理が不要で読みやすいため、繰り返し処理の基本を理解しやすいです。
一方で、次のような場合はfor文を使う必要があります。
C#for (int i = 0; i < names.Length; i++)
{
Console.WriteLine($"{i}: {names[i]}");
}
つまり、全要素を順番に処理するならforeach、番号や位置を使いたいならfor文、と覚えると分かりやすいです。
9. foreachとLINQの違い
C#では、foreachのほかにLINQを使ってデータを処理することもできます。
foreachとLINQは似た場面で使われることがありますが、役割が少し違います。
9-1. foreachは処理を書くための構文
foreachは、コレクションの要素を1つずつ取り出して、処理を実行するための構文です。
C#List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
foreach (int number in numbers)
{
Console.WriteLine(number);
}
この例では、Listの中身を1つずつ表示しています。
foreachは、表示、集計、条件分岐、メソッド呼び出しなど、処理の流れを自分で書きたいときに向いています。
C#int total = 0;
foreach (int number in numbers)
{
if (number % 2 == 0)
{
total += number;
}
}
Console.WriteLine(total);
9-2. LINQはデータを絞り込み・変換するための書き方
LINQは、コレクションのデータを絞り込んだり、変換したり、並び替えたりするための書き方です。
たとえば、偶数だけを取り出す場合はWhereを使います。
C#List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
var evenNumbers = numbers.Where(number => number % 2 == 0);
foreach (int number in evenNumbers)
{
Console.WriteLine(number);
}
実行結果は次の通りです。
C#2
4
各要素を2倍に変換する場合はSelectを使います。
C#var doubledNumbers = numbers.Select(number => number * 2);
foreach (int number in doubledNumbers)
{
Console.WriteLine(number);
}
LINQは、データの加工内容を短く表現できるのが特徴です。
9-3. WhereやSelectとforeachの使い分け
Whereは、条件に合う要素を絞り込むために使います。
C#var passedScores = scores.Where(score => score >= 80);
Selectは、要素を別の形に変換するために使います。
C#var messages = scores.Select(score => $"{score}点");
一方、foreachは、取り出した要素に対して処理を実行するために使います。
C#foreach (int score in passedScores)
{
Console.WriteLine(score);
}
条件で絞り込むだけならLINQ、絞り込んだ結果を表示したり別の処理を実行したりするならforeach、というように使い分けると分かりやすいです。
もちろん、簡単な条件ならforeachとifだけで書いても問題ありません。
C#foreach (int score in scores)
{
if (score >= 80)
{
Console.WriteLine(score);
}
}
読みやすい方を選びましょう。
9-4. LINQとforeachを組み合わせる例
LINQとforeachは組み合わせて使えます。
次の例では、80点以上の点数だけをLINQで絞り込み、foreachで表示しています。
C#List<int> scores = new List<int> { 65, 80, 92, 70, 88 };
var passedScores = scores.Where(score => score >= 80);
foreach (int score in passedScores)
{
Console.WriteLine($"{score}点は合格です");
}
実行結果は次の通りです。
C#80点は合格です
92点は合格です
88点は合格です
文字列のListでも同じように使えます。
C#List<string> names = new List<string> { "Tanaka", "Sato", "Suzuki", "Takahashi" };
var sNames = names.Where(name => name.StartsWith("S"));
foreach (string name in sNames)
{
Console.WriteLine(name);
}
LINQでデータを絞り込み、foreachで処理する書き方は、実務でもよく使われます。
9-5. 読みやすさを重視した選び方
foreachとLINQのどちらを使うか迷ったら、読みやすさを基準に選びましょう。
簡単な処理なら、foreachだけで十分です。
C#foreach (int score in scores)
{
if (score >= 80)
{
Console.WriteLine(score);
}
}
データを絞り込んだり変換したりする意図をはっきり示したい場合は、LINQが便利です。
C#var passedScores = scores.Where(score => score >= 80);
ただし、LINQを無理に使いすぎると、初心者には読みにくくなることもあります。
まずはforeachで処理の流れを理解し、慣れてきたらLINQも使えるようになるとよいでしょう。
10. foreachの実践サンプル集
ここでは、C#のforeachを使った実践的なサンプルを紹介します。
配列、List、Dictionary、条件付き集計、オブジェクトのプロパティ表示など、よく使うパターンを確認しましょう。
10-1. 配列の全要素を表示する
配列の全要素を表示する基本例です。
C#string[] languages = { "C#", "Java", "Python", "JavaScript" };
foreach (string language in languages)
{
Console.WriteLine(language);
}
実行結果は次の通りです。
C#C#
Java
Python
JavaScript
配列の要素数が増えても、foreachの書き方は変わりません。
10-2. Listから特定の文字列を探す
Listの中から特定の文字列を探す例です。
C#List<string> names = new List<string> { "田中", "佐藤", "鈴木", "高橋" };
string target = "鈴木";
bool found = false;
foreach (string name in names)
{
if (name == target)
{
found = true;
break;
}
}
if (found)
{
Console.WriteLine($"{target}さんが見つかりました");
}
else
{
Console.WriteLine($"{target}さんは見つかりませんでした");
}
実行結果は次の通りです。
C#鈴木さんが見つかりました
目的の要素が見つかったらbreakでループを終了している点がポイントです。
10-3. Dictionaryのキーと値を一覧表示する
Dictionaryのキーと値を一覧表示する例です。
C#Dictionary<string, string> users = new Dictionary<string, string>
{
{ "tanaka", "田中太郎" },
{ "sato", "佐藤花子" },
{ "suzuki", "鈴木一郎" }
};
foreach (var user in users)
{
Console.WriteLine($"ID: {user.Key}, 名前: {user.Value}");
}
実行結果の例は次の通りです。
C#ID: tanaka, 名前: 田中太郎
ID: sato, 名前: 佐藤花子
ID: suzuki, 名前: 鈴木一郎
user.KeyでID、user.Valueで名前を取得しています。
10-4. 条件に合う数値だけを合計する
条件に合う数値だけを合計する例です。
C#List<int> numbers = new List<int> { 10, 15, 20, 25, 30 };
int total = 0;
foreach (int number in numbers)
{
if (number % 2 == 0)
{
total += number;
}
}
Console.WriteLine($"偶数の合計: {total}");
実行結果は次の通りです。
C#偶数の合計: 60
number % 2 == 0で偶数かどうかを判定しています。
10-5. foreachでオブジェクトのプロパティを表示する
Listにオブジェクトを入れて、foreachでプロパティを表示する例です。
C#class Product
{
public string Name { get; set; }
public int Price { get; set; }
}
C#List<Product> products = new List<Product>
{
new Product { Name = "りんご", Price = 120 },
new Product { Name = "みかん", Price = 80 },
new Product { Name = "バナナ", Price = 150 }
};
foreach (Product product in products)
{
Console.WriteLine($"{product.Name}: {product.Price}円");
}
実行結果は次の通りです。
C#りんご: 120円
みかん: 80円
バナナ: 150円
実務では、ユーザー情報、商品情報、注文情報などをオブジェクトとしてListに入れ、foreachで処理する場面がよくあります。
11. foreachでよくあるエラーと解決方法
foreachを使っていると、いくつかよくあるエラーに出会います。
ここでは、初心者がつまずきやすいエラーと解決方法を紹介します。
11-1. Collection was modifiedの原因と対処法
foreach中にコレクションを変更すると、次のようなエラーが発生することがあります。
C#InvalidOperationException: Collection was modified; enumeration operation may not execute.
原因は、foreachで回している最中に、対象のListなどへ追加・削除を行ったことです。
C#List<int> numbers = new List<int> { 1, 2, 3, 4 };
foreach (int number in numbers)
{
if (number % 2 == 0)
{
numbers.Remove(number); // エラーの原因
}
}
解決方法の1つは、削除対象を別のListに集めてから削除することです。
C#List<int> numbers = new List<int> { 1, 2, 3, 4 };
List<int> removeNumbers = new List<int>();
foreach (int number in numbers)
{
if (number % 2 == 0)
{
removeNumbers.Add(number);
}
}
foreach (int number in removeNumbers)
{
numbers.Remove(number);
}
また、ListであればRemoveAllを使うと簡単です。
C#numbers.RemoveAll(number => number % 2 == 0);
11-2. NullReferenceExceptionの原因と対処法
foreachの対象がnullの場合、NullReferenceExceptionが発生します。
C#List<string> names = null;
foreach (string name in names)
{
Console.WriteLine(name);
}
対処法は、foreachの前にnullチェックを行うことです。
C#if (names != null)
{
foreach (string name in names)
{
Console.WriteLine(name);
}
}
また、変数を宣言するときに空のListを代入しておくと安全です。
C#List<string> names = new List<string>();
foreach (string name in names)
{
Console.WriteLine(name);
}
空のListなら、ループは実行されませんがエラーにもなりません。
11-3. 型が合わないときの確認ポイント
foreachでは、取り出す要素の型と変数の型が合っている必要があります。
たとえば、Listの中身がintなのに、stringとして取り出そうとするとエラーになります。
C#List<int> numbers = new List<int> { 1, 2, 3 };
foreach (string number in numbers) // エラー
{
Console.WriteLine(number);
}
正しくは次のように書きます。
C#foreach (int number in numbers)
{
Console.WriteLine(number);
}
型が分からない場合は、varを使うこともできます。
C#foreach (var number in numbers)
{
Console.WriteLine(number);
}
ただし、varは型を自動で推論するだけで、型が存在しないわけではありません。中身の型を理解しておくことは大切です。
11-4. 変更したつもりなのに値が変わらない原因
foreachで値を変更したつもりなのに、元のコレクションが変わらないことがあります。
たとえば、次のようなコードです。
C#List<int> numbers = new List<int> { 1, 2, 3 };
foreach (int number in numbers)
{
int changed = number * 2;
}
このコードでは、changedという新しい変数に2倍の値を入れているだけで、Listの中身は変更されません。
Listの要素そのものを変更したい場合は、for文を使います。
C#for (int i = 0; i < numbers.Count; i++)
{
numbers[i] = numbers[i] * 2;
}
オブジェクトのプロパティを変更する場合は、foreachでも変更できることがあります。
C#foreach (Product product in products)
{
product.Price += 100;
}
値型を扱っているのか、参照型のオブジェクトを扱っているのかによって挙動が変わる点に注意しましょう。
11-5. foreachが使えないオブジェクトの見分け方
foreachは、どんなオブジェクトにも使えるわけではありません。
基本的には、列挙できるオブジェクトに対して使えます。
配列やListはforeachで使えます。
C#int[] numbers = { 1, 2, 3 };
foreach (int number in numbers)
{
Console.WriteLine(number);
}
一方、単なる数値にはforeachを使えません。
C#int number = 10;
// foreach (int n in number) // エラー
// {
// Console.WriteLine(n);
// }
foreachが使えるかどうかは、「複数の要素を順番に取り出せるものか」を考えると分かりやすいです。
配列、List、Dictionary、HashSet、文字列などはforeachで使えます。
12. C# foreachに関するよくある質問
最後に、C#のforeachについて初心者が疑問に思いやすいポイントをQ&A形式で整理します。
12-1. foreachでインデックスは取得できる?
foreach自体には、インデックスを自動で取得する機能はありません。
ただし、カウンター変数を用意すればインデックスのように扱えます。
C#string[] names = { "田中", "佐藤", "鈴木" };
int index = 0;
foreach (string name in names)
{
Console.WriteLine($"{index}: {name}");
index++;
}
インデックスを中心に処理したい場合は、for文を使う方が分かりやすいです。
C#for (int i = 0; i < names.Length; i++)
{
Console.WriteLine($"{i}: {names[i]}");
}
12-2. foreachの中で要素を削除するには?
foreachで回しているコレクションから、その場で要素を削除するのは避けましょう。
C#foreach (string name in names)
{
if (name == "佐藤")
{
names.Remove(name); // エラーの原因
}
}
削除したい場合は、削除対象を別に集めてから削除するか、RemoveAllを使います。
C#names.RemoveAll(name => name == "佐藤");
または、削除用のListを用意します。
C#List<string> removeNames = new List<string>();
foreach (string name in names)
{
if (name == "佐藤")
{
removeNames.Add(name);
}
}
foreach (string name in removeNames)
{
names.Remove(name);
}
12-3. foreachとList.ForEachはどちらを使うべき?
初心者には、通常のforeach文がおすすめです。
C#foreach (string name in names)
{
Console.WriteLine(name);
}
List.ForEachは次のように書けます。
C#names.ForEach(name =>
{
Console.WriteLine(name);
});
List.ForEachは短く書ける場合もありますが、ラムダ式に慣れていないと読みにくくなります。
また、breakやcontinueを自然に使いたい場合は、通常のforeach文の方が扱いやすいです。
12-4. foreachは配列・List・Dictionary以外にも使える?
はい、使えます。
foreachは、配列、List、Dictionaryのほかにも、HashSetやQueue、文字列など、列挙できるオブジェクトに使えます。
C#string text = "ABC";
foreach (char c in text)
{
Console.WriteLine(c);
}
実行結果は次の通りです。
C#A
B
C
HashSetでも使えます。
C#HashSet<string> tags = new HashSet<string> { "C#", "foreach", "List" };
foreach (string tag in tags)
{
Console.WriteLine(tag);
}
初心者のうちは、まず配列、List、Dictionaryでの使い方をしっかり覚えましょう。
12-5. foreachは処理速度が遅い?
通常の開発では、foreachが遅いかどうかを過度に気にする必要はありません。
多くの場合、foreachは十分高速で、読みやすいコードを書きやすいというメリットがあります。
C#foreach (int number in numbers)
{
Console.WriteLine(number);
}
ただし、大量のデータを何度も処理する場合や、パフォーマンスが重要な処理では、実際に測定して判断することが大切です。
C#var watch = System.Diagnostics.Stopwatch.StartNew();
foreach (int number in numbers)
{
int result = number * 2;
}
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds);
初心者のうちは、まず正しく読みやすいコードを書くことを優先しましょう。
まとめ
C#のforeachは、配列、List、Dictionaryなどのコレクションから要素を1つずつ取り出して処理するための便利な構文です。
基本構文は次の形です。
C#foreach (型 変数名 in コレクション)
{
処理;
}
配列の要素を表示する場合は、次のように書けます。
C#string[] names = { "田中", "佐藤", "鈴木" };
foreach (string name in names)
{
Console.WriteLine(name);
}
Listでも同じように使えます。
C#List<int> numbers = new List<int> { 10, 20, 30 };
foreach (int number in numbers)
{
Console.WriteLine(number);
}
Dictionaryでは、KeyとValueを使ってキーと値を取り出します。
C#Dictionary<string, int> scores = new Dictionary<string, int>
{
{ "田中", 80 },
{ "佐藤", 90 }
};
foreach (var score in scores)
{
Console.WriteLine($"{score.Key}: {score.Value}");
}
foreachは、インデックスを意識せずに全要素を処理できるため、初心者にも読みやすいコードを書きやすいのが特徴です。
一方で、foreach中にコレクションを追加・削除するとエラーになることがあります。また、インデックスが必要な処理や要素を直接変更したい処理では、for文の方が向いている場合もあります。
まずは、配列やListの全要素を表示する簡単な例から練習し、慣れてきたらDictionary、break、continue、LINQとの組み合わせも覚えていきましょう。

