共用方式為


迭代語句 - forforeachdowhile

迭代語句會反覆執行語句或語句區塊。 當指定的布爾表示式評估為for時,會執行其程式碼。 foreach語句會列舉集合的元素,並針對集合的每個元素執行其主體。 do語句依條件執行其主體一次或多次。 while語句根據條件執行其程式碼區段零次或多次。

在反覆專案語句主體內的任何時間點,您可以使用 語句來中斷迴圈break。 您可以使用continue語句在迴圈中移至下一個反覆項次。

for 陳述式

當指定的布爾表達式評估為 for 時,true 將執行單一語句或語句區塊。 下列範例顯示 for 在整數計數器小於三時執行的語句:

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

上述範例顯示 語句的 for 元素:

  • 在進入迴圈之前,只會執行一次的區段是初始化表達式。 一般而言,您會在該區段中宣告並初始化區域迴圈變數。 宣告的變數無法從語句外部 for 存取。

    上述範例中的 初始化運算式 區段會宣告並初始化整數計數器變數:

    int i = 0
    
  • 條件區段,判斷迴圈中的下一個反覆專案是否應該執行。 如果評估為 true 或不存在,則執行下一個迴圈,否則結束迴圈。 條件區段必須是布爾表達式。

    上述範例中的 condition 區段會檢查計數器值是否小於三個:

    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 = new() { 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 陳述式

當指定的布爾表達式評估為 do 時,true 將執行單一語句或語句區塊。 因為該表達式會在每次執行循環之後進行評估,因此 do 迴圈會執行一或多次。 迴圈 dowhile 迴圈不同,迴圈會執行零次或多次。

以下範例展示了此語句的使用方式:do

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

while 陳述式

當指定的布爾表達式評估為 while 時,true 將執行單一語句或語句區塊。 因為該表達式會在每次執行迴圈之前進行評估,因此 while 迴圈會執行零次或多次。 迴圈 whiledo 迴圈不同,迴圈會執行一或多次。

以下範例展示了此語句的使用方式:while

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

C# 語言規格

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

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

另請參閱