反覆運算陳述式:forforeachdowhile

反覆運算陳述式會重複執行陳述式或陳述式區塊。 for 陳述式當指定的布林運算式評估為 true 時,執行其主體。 foreach 陳述式列舉集合元素,並針對集合的每個元素執行其主體。 do 陳述式有條件地執行其主體一或多次。 while 陳述式有條件地執行其主體零或多次。

在反覆運算陳述式主體的任意點,您均可使用 break 陳述式中斷迴圈。 您可以使用 continue 陳述式,逐步執行迴圈中的下一個反覆運算。

for 陳述式

當指定的布林運算式評估為 true 時,for 陳述式便會執行陳述式或陳述式區塊。 下列範例顯示當整數計數器小於三時,執行其主體的 for 陳述式:

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

上述範例顯示 for 陳述式的元素:

  • 在進入迴圈之前只執行一次的「初始設定式」區段。 一般而言,您會在該區段中宣告和初始化局部迴圈變數。 宣告的變數無法從 for 陳述式外部存取。

    上述範例中的「初始設定式」區段會宣告,並初始化整數計數器變數:

    int i = 0
    
  • 「條件」區段確認是否應執行迴圈中的下一個反覆運算。 如果它評估為 true 或不存在,則會執行下一個反覆運算;否則會結束迴圈。 「條件」區段必須是布林運算式。

    上述範例中的「條件」區段會檢查計數器值是否小於三:

    i < 3
    
  • 「迭代器」區段會定義迴圈主體每次執行之後的狀況。

    上述範例中的「迭代器」區段會遞增計數器:

    i++
    
  • 迴圈的主體必須是陳述式或陳述式區塊。

迭代器區段可包含下列零個或多個陳述式運算式,並以逗號分隔:

如果您未在初始設定式區段中宣告迴圈變數,您也可以在初始設定式區段中使用上述清單中的零個或多個運算式。 下列範例示範幾個較少見的初始設定式和迭代器區段的用法︰將值指派給初始設定式區段中的外部變數、在初始設定式和迭代器區段中叫用方法,以及在迭代器區段中變更兩個變數的值:

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.IEnumerableSystem.Collections.Generic.IEnumerable<T> 介面的元素,執行其中的陳述式或陳述式區塊,如下列範例所示:

List<int> fibNumbers = [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 方法。 GetEnumerator方法也可以是型別的擴充方法
  • GetEnumerator 方法的傳回型別有公開的 Current 屬性,且公開無參數的 MoveNext 方法的傳回型別為 bool

下列範例使用 foreach 陳述式搭配不實作任何介面的 System.Span<T> 型別執行個體:

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

如果列舉程式的 Current 屬性會傳回參考傳回值 (ref T其中T 是集合元素的型別),您可以使用 refref 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 陳述式的來源集合為空白,則陳述式foreach的主體不會執行,且會跳過該主體。 若將 foreach 陳述式套用到 null,則會擲回 NullReferenceException

await foreach

您可以使用 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 擴充方法。 如需同步處理內容和擷取目前內容的詳細資訊,請參閱取用以工作為基礎的非同步模式。 如需非同步資料流的詳細資訊,請參閱非同步資料流教學課程

反覆運算變數的型別

您可以使用var 關鍵字,讓編譯器推斷 foreach 陳述式中的反覆運算變數的型別,如下列程式碼所示:

foreach (var item in collection) { }

注意

var 類型可由編譯程式推斷為可為 Null 的參考型別,視啟用可為 Null 感知的內容,以及初始化表達式的類型是否為參考型別而定。 如需詳細資訊,請參閱隱含類型區域變數

您也可以明確指定反覆運算變數的型別,如下列程式碼所示:

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

在上述形式中,集合元素的型別 T 必須隱含或明確可轉換成反覆運算變數型別 V。 如果從 TV 的明確轉換在執行階段失敗,foreach 陳述式會擲回 InvalidCastException。 例如,如果 T 是非密封類別型別,V 可以是任何介面型別,甚至是 T 未實作的介面型別。 在執行階段,集合元素的型別可能衍生自 T 且實際實作的V 。 如果不是這種案例,則會擲回 InvalidCastException

do 陳述式

當指定的布林運算式評估為 true 時,do 陳述式便會執行陳述式或陳述式區塊。 因為運算式會在每次迴圈執行後評估,所以 do 迴圈會執行一或多次。 do 迴圈與執行零次或多次的 while 迴圈不同。

下列範例會示範 do 陳述式的用法:

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

while 陳述式

當指定的布林運算式評估為 true 時,while 陳述式便會執行陳述式或陳述式區塊。 運算式是在每次執行迴圈之前評估,因此 while 迴圈會執行零次以上。 while 迴圈與執行一次或多次的 do 迴圈不同。

下列範例會示範 while 陳述式的用法:

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

C# 語言規格

如需詳細資訊,請參閱 C# 語言規格的下列幾節:

如需這些功能的詳細資訊,請參閱下列功能提案筆記:

另請參閱