反覆運算陳述式:for
、foreach
、do
和 while
反覆運算陳述式會重複執行陳述式或陳述式區塊。 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.IEnumerable 或 System.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
是集合元素的型別),您可以使用 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
陳述式的來源集合為空白,則陳述式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
。 如果從 T
到 V
的明確轉換在執行階段失敗,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# 語言規格的下列幾節:
如需這些功能的詳細資訊,請參閱下列功能提案筆記: