共用方式為


Jump 語句 - break、、 returncontinuegoto

jump 語句會無條件傳輸控件。 語句會break終止最接近的封入反覆運算語句switch語句語句continue會啟動最接近封入反覆運算語句的新反覆專案。 語句return會終止其出現的函式執行,並將控制權傳回給呼叫端。 語句會將goto控件傳送至以標籤示的語句。

如需擲回例外狀況並無條件傳輸控件之語句的相關信息throw,請參閱throw例外狀況處理語句一文的 語句一節。

break 陳述式

語句會break終止最接近的封入反覆運算語句 (也就是 、 forforeachwhiledo 循環) 或 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下列範例所示,語句會啟動最接近封入反覆運算語句的新反覆專案(也就是 、forforeachwhiledo 迴圈):

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 傳回型別為 TaskValueTask,您可以使用不含表達式的 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 的實值類型
  • 傳回值不能是常數、列舉成員、屬性的 class by-value 傳回值,或 或 struct的方法。

此外,異步方法不允許參考傳回值。 異步方法可能會在完成執行之前傳回,而其傳回值仍然未知。

回參考傳回值 的方法必須:

  • 在傳回型別前面包含 ref 關鍵詞。
  • 方法主體中的每個 return 語句都會在傳回實例的名稱前面包含 ref 關鍵詞。

下列範例顯示滿足這些條件的方法,並傳回名為 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 參考變數中,以避免複製傳回的值。

下列範例會定義具有兩StringBook欄位TitleAuthor的類別。 它也會定義類別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# 語言規格的下列幾節:

另請參閱