foreach
IEnumerable
、IEnumerable<T>
、IEnumerator
、またはIEnumerator<T>
(または実際には互換性のあるCurrent
プロパティとMoveNext()
メソッドを実装するクラスを持つオブジェクト)を実装する任意のオブジェクトを列挙します。の構文foreach
は次のとおりです。
foreach (type variable in enumerable) { ... }
type
新しいvariable
変数の型です。(使用する既存の変数が既にある場合は、型を省略します。)
ループの本体は、列挙可能なオブジェクトごとに実行され、反復変数 (ここではvariable
) には反復ごとにオブジェクトが含まれます。
for
はるかに汎用的で、次のパターンに従います。
for (initial-statements; loop-condition; post-iteration-actions) {
body
}
これは、次とほぼ同じです。
initial-statements
while (loop-condition) {
body
post-iteration-actions
}
for
次の例のように、配列を扱うときにループが発生する場合があります。
for (int index = 0; index < array.Length; index++) {
Console.WriteLine(array[index]);
}
これは次と同じです。
{
int index = 0;
while (index < array.Length) {
Console.WriteLine(array[index]);
index++;
}
}
(foreach
これはより高速であるため、配列を使用することは、同様のインデックスベースの反復を使用するようにコンパイラによって最適化されることに注意してください。したがって、3 つの方法はすべて、配列を列挙するときに同等のパフォーマンスと実行時セマンティクスを持つ必要があります。)
必要に応じて、詳細情報:
foreach
while
実際には単なる構文糖衣であり、簡単にループに変換できます。
foreach (object x in y) {
Console.WriteLine(x);
}
これは実際には次のことを意味します。
var enumerator = y.GetEnumerator();
try {
object x; // See footnote 1
while (enumerator.MoveNext()) {
x = enumerator.Current;
Console.WriteLine(x);
}
} finally {
((IDisposable)enumerator).Dispose();
}
ただし、enumerator
変数には名前がなく、隠されています。
foreach
存在する理由は明らかです。今日それを使用する場合はどこでも、そうでなければ、この恐ろしく冗長なボイラープレート コードを書かなければならないでしょう。 foreach
列挙子を取得し、各反復でテストMoveNext()
し、列挙子の現在の値を抽出し、反復が完了した後に列挙子を破棄します。
1この変数は、C# 5 以降、実際にはループ内で意味的に宣言されています。この例は、C# 4 以前のバージョンで正確です。