Jump 語句 -
jump 語句會無條件傳輸控件。 語句會break終止最接近的封入反覆運算語句或switch語句。
語句continue會啟動最接近封入反覆運算語句的新反覆專案。
語句return會終止其出現的函式執行,並將控制權傳回給呼叫端。 語句會將goto控件傳送至以標籤示的語句。
如需擲回例外狀況並無條件傳輸控件之語句的相關信息throw,請參閱throw例外狀況處理語句一文的 語句一節。
break 陳述式
語句會break終止最接近的封入反覆運算語句 (也就是 、 forforeach、 while或 do 循環) 或 switch 語句。 如果有任何的話,語句會將 break 控制權傳送至結尾語句後面的 語句。
int[] numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
foreach (int number in numbers)
{
if (number == 3)
{
break;
}
Console.Write($"{number} ");
}
Console.WriteLine();
Console.WriteLine("End of the example.");
// Output:
// 0 1 2
// End of the example.
在巢狀迴圈中 break ,語句只會終止包含它的最內部迴圈,如下列範例所示:
for (int outer = 0; outer < 5; outer++)
{
for (int inner = 0; inner < 5; inner++)
{
if (inner > outer)
{
break;
}
Console.Write($"{inner} ");
}
Console.WriteLine();
}
// Output:
// 0
// 0 1
// 0 1 2
// 0 1 2 3
// 0 1 2 3 4
當您在迴圈內使用 switch 語句時, break switch 區段結尾的 語句只會將控制權移出 switch 語句。 包含語句的 switch 迴圈不會受到影響,如下列範例所示:
double[] measurements = [-4, 5, 30, double.NaN];
foreach (double measurement in measurements)
{
switch (measurement)
{
case < 0.0:
Console.WriteLine($"Measured value is {measurement}; too low.");
break;
case > 15.0:
Console.WriteLine($"Measured value is {measurement}; too high.");
break;
case double.NaN:
Console.WriteLine("Failed measurement.");
break;
default:
Console.WriteLine($"Measured value is {measurement}.");
break;
}
}
// Output:
// Measured value is -4; too low.
// Measured value is 5.
// Measured value is 30; too high.
// Failed measurement.
continue 陳述式
如continue下列範例所示,語句會啟動最接近封入反覆運算語句的新反覆專案(也就是 、forforeach、 while或 do 迴圈):
for (int i = 0; i < 5; i++)
{
Console.Write($"Iteration {i}: ");
if (i < 3)
{
Console.WriteLine("skip");
continue;
}
Console.WriteLine("done");
}
// Output:
// Iteration 0: skip
// Iteration 1: skip
// Iteration 2: skip
// Iteration 3: done
// Iteration 4: done
return 陳述式
語句 return 會終止其出現的函式執行,並將控件和函式的結果傳回給呼叫端。
如果函式成員未計算值,您可以使用 return 不含表達式的 語句,如下列範例所示:
Console.WriteLine("First call:");
DisplayIfNecessary(6);
Console.WriteLine("Second call:");
DisplayIfNecessary(5);
void DisplayIfNecessary(int number)
{
if (number % 2 == 0)
{
return;
}
Console.WriteLine(number);
}
// Output:
// First call:
// Second call:
// 5
如上述範例所示,您通常會使用不含表達式的 return 語句來提早終止函式成員。 如果函式成員未包含 return 語句,則會在最後一個語句執行之後終止。
如果函式成員計算值,您可以使用 return 語句搭配表達式,如下列範例所示:
double surfaceArea = CalculateCylinderSurfaceArea(1, 1);
Console.WriteLine($"{surfaceArea:F2}"); // output: 12.57
double CalculateCylinderSurfaceArea(double baseRadius, double height)
{
double baseArea = Math.PI * baseRadius * baseRadius;
double sideArea = 2 * Math.PI * baseRadius * height;
return 2 * baseArea + sideArea;
}
return當語句具有表達式時,除非該表達式是異步的,否則該運算式必須隱含轉換成函式成員的傳回型別。 從函 async 式傳回的 Task<TResult> 表達式必須隱含轉換成 或 ValueTask<TResult>的型別自變數,無論哪一種是函式的傳回型別。 如果函式的 async 傳回型別為 Task 或 ValueTask,您可以使用不含表達式的 return 語句。
Ref 傳回
根據預設, return 語句會傳回表達式的值。 您可以傳回變數的參考。 參考傳回值(或 ref 傳回值)是方法透過呼叫端傳回的值。 也就是說,呼叫端可以修改方法傳回的值,而該變更會反映在所呼叫方法中的對象狀態。 若要這樣做,請使用 return 語句搭配 ref 關鍵詞,如下列範例所示:
int[] xs = new int [] {10, 20, 30, 40 };
ref int found = ref FindFirst(xs, s => s == 30);
found = 0;
Console.WriteLine(string.Join(" ", xs)); // output: 10 20 0 40
ref int FindFirst(int[] numbers, Func<int, bool> predicate)
{
for (int i = 0; i < numbers.Length; i++)
{
if (predicate(numbers[i]))
{
return ref numbers[i];
}
}
throw new InvalidOperationException("No element satisfies the given condition.");
}
參考傳回值可讓方法將變數的參考傳回給呼叫端,而不是傳回值。 接著,呼叫端可以選擇將傳回的變數視為值或傳址傳回的變數。 呼叫端可以建立新的變數,這個變數本身是傳回值的參考,稱為 ref 區域。 參考傳回值表示方法會將參考 (或別名) 傳回給某些變數。 該變數的範圍必須包含方法。 該變數的存留期必須超出 方法的傳回範圍。 呼叫端對 方法的傳回值所做的修改,是針對 方法所傳回的變數進行修改。
宣告方法會傳回 參考傳回值 ,表示方法會將別名傳回給變數。 設計意圖通常是呼叫程式代碼會透過別名存取該變數,包括修改變量。 傳址傳回的方法不能有傳回型別 void。
為了讓呼叫端修改物件的狀態,參考傳回值必須儲存至明確定義為 參考變數的變數。
傳 ref 回值是所呼叫方法範圍中另一個變數的別名。 您可以將 ref 傳回的任何用法解譯為使用別名的變數:
- 當您指派其值時,您會將值指派給其別名的變數。
- 當您讀取其值時,您會讀取其別名變數的值。
- 如果您 以傳址方式傳回它,則會將別名傳回給相同的變數。
- 如果您 以傳址方式將它傳遞給另一個方法,則會將參考傳遞給它別名的變數。
- 當您建立 ref 區域 別名時,會將新的別名設為相同的變數。
ref 傳回必須是呼叫方法的 ref-safe-context 。 這表示:
- 傳回值必須具有超出方法執行範圍的存留期。 換句話說,它不能是傳回它的方法中的局部變數。 它可以是類別的實例或靜態字段,也可以是傳遞至 方法的自變數。 嘗試傳回局部變數會產生編譯程序錯誤 CS8168:「無法以傳址方式傳回本機 'obj',因為它不是 ref local。」
- 傳回值不能是常值
null。 具有 ref 傳回的方法可以將別名傳回給變數,變數的值目前null為 (uninstantiated) 值或可為 Null 的實值類型 。 - 傳回值不能是常數、列舉成員、屬性的
classby-value 傳回值,或 或struct的方法。
此外,異步方法不允許參考傳回值。 異步方法可能會在完成執行之前傳回,而其傳回值仍然未知。
傳 回參考傳回值 的方法必須:
下列範例顯示滿足這些條件的方法,並傳回名為 p的對象參考Person:
public ref Person GetContactInformation(string fname, string lname)
{
// ...method implementation...
return ref p;
}
以下是更完整的 ref 傳回範例,同時顯示方法簽章和方法主體。
public static ref int Find(int[,] matrix, Func<int, bool> predicate)
{
for (int i = 0; i < matrix.GetLength(0); i++)
for (int j = 0; j < matrix.GetLength(1); j++)
if (predicate(matrix[i, j]))
return ref matrix[i, j];
throw new InvalidOperationException("Not found");
}
呼叫的方法也可以將傳回值宣告為 ref readonly ,以傳址方式傳回值,並強制呼叫端程式代碼無法修改傳回的值。 呼叫方法可以藉由將值儲存在本機 ref readonly 參考變數中,以避免複製傳回的值。
下列範例會定義具有兩String個Book欄位Title和Author的類別。 它也會定義類別BookCollection,其中包含物件的私用數位。Book 個別書籍物件會藉由呼叫其 GetBookByTitle 方法,以傳回傳址。
public class Book
{
public string Author;
public string Title;
}
public class BookCollection
{
private Book[] books = { new Book { Title = "Call of the Wild, The", Author = "Jack London" },
new Book { Title = "Tale of Two Cities, A", Author = "Charles Dickens" }
};
private Book nobook = null;
public ref Book GetBookByTitle(string title)
{
for (int ctr = 0; ctr < books.Length; ctr++)
{
if (title == books[ctr].Title)
return ref books[ctr];
}
return ref nobook;
}
public void ListBooks()
{
foreach (var book in books)
{
Console.WriteLine($"{book.Title}, by {book.Author}");
}
Console.WriteLine();
}
}
當呼叫端將 方法傳 GetBookByTitle 回的值儲存為 ref 區域時,呼叫端對傳回值所做的變更會反映在 物件中 BookCollection ,如下列範例所示。
var bc = new BookCollection();
bc.ListBooks();
ref var book = ref bc.GetBookByTitle("Call of the Wild, The");
if (book != null)
book = new Book { Title = "Republic, The", Author = "Plato" };
bc.ListBooks();
// The example displays the following output:
// Call of the Wild, The, by Jack London
// Tale of Two Cities, A, by Charles Dickens
//
// Republic, The, by Plato
// Tale of Two Cities, A, by Charles Dickens
goto 陳述式
語句會將 goto 控件傳輸至以標籤示的語句,如下列範例所示:
var matrices = new Dictionary<string, int[][]>
{
["A"] =
[
[1, 2, 3, 4],
[4, 3, 2, 1]
],
["B"] =
[
[5, 6, 7, 8],
[8, 7, 6, 5]
],
};
CheckMatrices(matrices, 4);
void CheckMatrices(Dictionary<string, int[][]> matrixLookup, int target)
{
foreach (var (key, matrix) in matrixLookup)
{
for (int row = 0; row < matrix.Length; row++)
{
for (int col = 0; col < matrix[row].Length; col++)
{
if (matrix[row][col] == target)
{
goto Found;
}
}
}
Console.WriteLine($"Not found {target} in matrix {key}.");
continue;
Found:
Console.WriteLine($"Found {target} in matrix {key}.");
}
}
// Output:
// Found 4 in matrix A.
// Not found 4 in matrix B.
如上述範例所示,您可以使用 goto 語句來退出巢狀迴圈。
小提示
當您使用巢狀循環時,請考慮將個別迴圈重構為不同的方法。 這可能會導致沒有語句的更簡單、更容易閱讀的程序 goto 代碼。
您也可以使用 goto 語句中的 switch 語句 ,將控件傳送至具有常數大小寫卷標的 switch 區段,如下列範例所示:
using System;
public enum CoffeeChoice
{
Plain,
WithMilk,
WithIceCream,
}
public class GotoInSwitchExample
{
public static void Main()
{
Console.WriteLine(CalculatePrice(CoffeeChoice.Plain)); // output: 10.0
Console.WriteLine(CalculatePrice(CoffeeChoice.WithMilk)); // output: 15.0
Console.WriteLine(CalculatePrice(CoffeeChoice.WithIceCream)); // output: 17.0
}
private static decimal CalculatePrice(CoffeeChoice choice)
{
decimal price = 0;
switch (choice)
{
case CoffeeChoice.Plain:
price += 10.0m;
break;
case CoffeeChoice.WithMilk:
price += 5.0m;
goto case CoffeeChoice.Plain;
case CoffeeChoice.WithIceCream:
price += 7.0m;
goto case CoffeeChoice.Plain;
}
return price;
}
}
在語句中 switch ,您也可以使用 語句 goto default; ,將控制權傳送至具有標籤的 default switch 區段。
如果目前函式成員中沒有具有指定名稱的標籤,或 goto 語句不在標籤內,則會發生編譯時期錯誤。 也就是說,您無法使用 goto 語句將控制權移出目前函式成員或任何巢狀範圍。
C# 語言規格
如需詳細資訊,請參閱 C# 語言規格的下列幾節: