foreach文
ループ文その3
foreach文はループ文の中でもやや特殊なループ文です。
foreach文は「あるデータの集合に対して一通り処理を実行する」というループ文です。
「データの集合」とは、今まで説明してきた機能では「配列」が該当します。
「データの集合」はコレクションといいます。
static void Main(string[] args)
{
int[] numbers = new int[] { 0, 1, 2, 3, 4, 5 };
foreach(int num in numbers)
{
Console.WriteLine(num * 2);
}
}
0 2 4 6 8 10
このコードは配列の各要素を二倍して表示するだけの単純なものです。
5行目のforeach文で、配列numbersから順番に要素を取りだしています。
foreach(データ型 変数名 in コレクション)
{
}
foreach文は、指定したコレクションから要素をひとつずつ取り出して文を実行します。
これをコレクションの要素数の回数だけ繰り返します。
取り出した要素は変数(繰り返し変数)に格納され、foreachブロックの中で使用できます。
データ型と変数名は自由に決定できますが、当然ながら変換できない型は指定できません。
(後述)
foreach文はfor文やwhile文のようにループ終了のための条件判定式がありません。
そのため無限ループに陥る危険性がなく、「すべての要素に一回ずつアクセスする」という目的でのループならばforeach文の使用が適しています。
繰り返し変数は書き換えできない
foreach文の繰り返し変数を書き換えることは禁止されています。
static void Main(string[] args)
{
int[] numbers = new int[] { 0, 1, 2, 3, 4, 5 };
foreach (int num in numbers)
{
//エラー
num *= 2;
Console.WriteLine(num);
}
}
つまりforeach文ではコレクションの要素を書き換えることはできないということです。
書き換えをする場合はfor文やwhile文などの別の手段を用いる必要があります。
要素が参照型の場合はその参照(アドレス)にひもづけられたデータは書き換え可能です。
(二次元配列の二次元目やクラスのフィールドなど)
class TestClass
{
public int num;
public string str;
public TestClass(int num, string str)
{
this.num = num;
this.str = str;
}
}
static void Main(string[] args)
{
int[][] arr = new int[][]
{
new int[]{ 1, 2, 3 },
new int[]{ 4, 5, 6 }
};
List<TestClass> lstTc = new List<TestClass>()
{
new TestClass(1, "aaa"),
new TestClass(2, "bbb"),
new TestClass(3, "ccc")
};
foreach (var v in arr)
{
v[0] *= 2;
}
foreach (var v in lstTc)
{
v.num *= 2;
}
}
繰り返し変数のデータ型
foreachの繰り返し変数は通常の変数と同じようにデータ型を記述しますが、変換が可能であれば指定したコレクションと同一のデータ型を指定する必要はありません。
このとき目的のデータ型に自動的にキャストされます。
static void Main(string[] args)
{
int[] numbers = new int[] { 0, 1, 2, 3, 4, 5 };
foreach(short num in numbers)
{
Console.WriteLine(num * 2);
}
}
型推論
繰り返し変数のデータ型には型推論(var)を使用できます。
static void Main(string[] args)
{
int[] numbers = new int[] { 0, 1, 2, 3, 4, 5 };
foreach(var num in numbers)
{
Console.WriteLine(num * 2);
}
}
これで指定されたコレクションから自動的に型を推測してデータ型を決定してくれます。
C#のコレクションはデータ型名がやたらと長いものもあるので、型推論を使用すると便利です。