反復ステートメント (C# リファレンス)

次のステートメントは、ステートメントまたはステートメントのブロックを繰り返し実行します。

反復ステートメントの本体内の任意の位置で、break ステートメントを使用してループから抜けたり、continue ステートメントを使用してループの次の反復に進んだりできます。

for ステートメント

for ステートメントでは、指定されたブール式が true と評価される間、ステートメントまたはステートメント ブロックが実行されます。 次の例では、整数カウンターが 3 未満の間は本体を実行する for ステートメントを示します。

for (int i = 0; i < 3; i++)
{
    Console.Write(i);
}
// Output:
// 012

前の例では、for ステートメントの要素が示されています。

  • ループに入る前に 1 回だけ実行される "初期化子" セクション。 通常は、そのセクションでローカル ループ変数を宣言して初期化します。 宣言された変数に、for ステートメントの外部からアクセスすることはできません。

    前の例の "初期化子" セクションでは、整数カウンター変数が宣言され、初期化されています。

    int i = 0
    
  • ループの次の反復を実行する必要があるかどうかを決定する "条件" セクション。 それが true と評価された場合、または存在しない場合は、次の反復が実行され、それ以外の場合はループが終了します。 "条件" セクションは、ブール式にする必要があります。

    前の例の "条件" セクションでは、カウンターの値が 3 未満かどうかチェックされています。

    i < 3
    
  • ループの本体の実行が終わるたびに行われる処理が定義されている "反復子" セクション。

    前の例の "反復子" セクションでは、カウンターがインクリメントされます。

    i++
    
  • ループの本体。ステートメントまたはステートメントのブロックである必要があります。

反復子セクションには、次のステートメント式を 0 個以上、コンマで区切って含めることができます。

初期化子セクションでループ変数を宣言しない場合、初期化子セクションの前の一覧にある 0 個以上の式を使用することもできます。 次に示すのは、初期化子セクションと反復子セクションのあまり一般的ではない使用例です。初期化子セクションで外部変数に値を代入し、初期化子セクションと反復子セクションの両方でメソッドを呼び出し、反復子セクションで 2 つの変数の値を変更しています。

int i;
int j = 3;
for (i = 0, Console.WriteLine($"Start: i={i}, j={j}"); i < j; i++, j--, Console.WriteLine($"Step: i={i}, j={j}"))
{
    //...
}
// Output:
// Start: i=0, j=3
// Step: i=1, j=2
// Step: i=2, j=1

for ステートメントのすべてのセクションは省略可能です。 たとえば、次のコードでは無限 for ループを定義しています。

for ( ; ; )
{
    //...
}

foreach ステートメント

foreach ステートメントは、次の例のように、System.Collections.IEnumerable または System.Collections.Generic.IEnumerable<T> インターフェイスを実装している型のインスタンス内の要素ごとに、ステートメントまたはステートメントのブロックを実行します。

var fibNumbers = new List<int> { 0, 1, 1, 2, 3, 5, 8, 13 };
foreach (int element in fibNumbers)
{
    Console.Write($"{element} ");
}
// Output:
// 0 1 1 2 3 5 8 13

foreach ステートメントは、これらの型に制限されません。 これは次の条件を満たす任意の型のインスタンスと共に使用できます。

  • 型には、パラメーターなしのパブリック GetEnumerator メソッドがあります。 C# 9.0 以降では、GetEnumerator メソッドを型の拡張メソッドにすることができます。
  • GetEnumerator メソッドの戻り値の型に、パブリック プロパティ Current と、戻り値の型が bool であるパラメーターなしのパブリック メソッド MoveNext がある。

次の例では、何のインターフェイスも実装していない System.Span<T> 型のインスタンスを使用して、foreach ステートメントを使用します。

Span<int> numbers = new int[] { 3, 14, 15, 92, 6 };
foreach (int number in numbers)
{
    Console.Write($"{number} ");
}
// Output:
// 3 14 15 92 6

C# 7.3 以降、列挙子の Current プロパティによって、参照戻り値 (ref T。この場合、T はコレクション要素の型です) が返される場合、次の例のように、ref または ref readonly 修飾子を使用して繰り返し変数を宣言することができます。

Span<int> storage = stackalloc int[10];
int num = 0;
foreach (ref int item in storage)
{
    item = num++;
}
foreach (ref readonly var item in storage)
{
    Console.Write($"{item} ");
}
// Output:
// 0 1 2 3 4 5 6 7 8 9

foreach ステートメントを null に適用した場合、NullReferenceException がスローされます。 foreach ステートメントのソース コレクションが空の場合、foreach ステートメントの本体は実行されず、スキップされます。

await foreach

C# 8.0 以降、await foreach ステートメントを使用して、データの非同期ストリーム、つまり、IAsyncEnumerable<T> インターフェイスを実装するコレクション型を使用できます。 次の要素が非同期で取得されている限り、ループの各反復は中断される可能性があります。 await foreach ステートメントを使用する方法の例を次に示します。

await foreach (var item in GenerateSequenceAsync())
{
    Console.WriteLine(item);
}

次の条件を満たす任意の型のインスタンスと共に、await foreach ステートメントを使用することもできます。

  • 型には、パラメーターなしのパブリック GetAsyncEnumerator メソッドがあります。 そのメソッドは、型の拡張メソッドでもかまいません。
  • GetAsyncEnumerator メソッドの戻り値の型に、パブリック Current プロパティと、パラメーターなしのパブリック MoveNextAsync メソッドがあり、そのメソッドの戻り値の型が Task<bool>ValueTask<bool>、または awaiter の GetResult メソッドが bool 値を返すその他の待機可能型のいずれかです。

既定では、ストリーム要素はキャプチャされたコンテキストで処理されます。 コンテキストのキャプチャを無効にする場合は、TaskAsyncEnumerableExtensions.ConfigureAwait 拡張メソッドを使用します。 同期コンテキストおよび現在のコンテキストのキャプチャについての詳細は、「タスク ベースの非同期パターンの利用」を参照してください。 非同期ストリームの詳細については、「C# 8.0 の新機能」の記事の「非同期ストリーム」セクションを参照してください。

繰り返し変数の型

次のコードに示すように、var キーワードを使用して、コンパイラによって foreach ステートメントの反復変数の型が推論されるようにすることができます。

foreach (var item in collection) { }

次のコードに示すように、繰り返し変数の型を明示的に指定することもできます。

IEnumerable<T> collection = new T[5];
foreach (V item in collection) { }

前の形式では、コレクション要素の型 T は、繰り返し変数の型 V に暗黙的または明示的に変換できる必要があります。 T から V への明示的な変換が実行時に失敗した場合、foreach ステートメントから InvalidCastException がスローされます。 たとえば、T が非シール クラス型の場合、V は任意のインターフェイス型にすることができ、T で実装されないものにすることもできます。 実行時に、コレクション要素の型は T から派生したものである可能性があり、実際には V を実装します。 そうでない場合は、InvalidCastException がスローされます。

do ステートメント

do ステートメントでは、指定されたブール式が true と評価される間、ステートメントまたはステートメント ブロックが実行されます。 ループの各実行の後に式が評価されるため、do ループは 1 回以上実行されます。 while ループは、これとは異なり、0 回以上実行されます。

do ステートメントの使用方法の例を次に示します。

int n = 0;
do
{
    Console.Write(n);
    n++;
} while (n < 5);
// Output:
// 01234

while ステートメント

while ステートメントでは、指定されたブール式が true と評価される間に、ステートメントまたはステートメント ブロックが実行されます。 ループの各実行の前に式が評価されるため、while ループは 0 回以上実行されます。 do ループは、これとは異なり、1 回以上実行されます。

while ステートメントの使用方法の例を次に示します。

int n = 0;
while (n < 5)
{
    Console.Write(n);
    n++;
}
// Output:
// 01234

C# 言語仕様

詳細については、「C# 言語仕様」の次のセクションを参照してください。

C# 8.0 以降に追加された機能の詳細については、機能の提案に関する次の記述を参照してください。

関連項目