Pernyataan lompat - break, continue, return, dan goto

Pernyataan lompat mentransfer kontrol tanpa syarat. Pernyataan mengakhiri pernyataan atau switch pernyataan iterasi yang menutupi terdekat.break Pernyataan memulai continue iterasi baru dari pernyataan iterasi penutup terdekat. Pernyataan return mengakhiri eksekusi fungsi di mana ia muncul dan mengembalikan kontrol ke pemanggil. Pernyataan mentransfer goto kontrol ke pernyataan yang ditandai oleh label.

Untuk informasi tentang throw pernyataan yang melempar pengecualian dan kontrol transfer tanpa syarat juga, lihat throwbagian pernyataan dari artikel Pernyataan penanganan pengecualian.

Pernyataan break

break statement mengakhiri statement iterasi enclosing terdekat (yaitu, for, foreach. while, atau loop do) atau switch statement. break statement mentransfer kontrol ke statement yang mengikuti statement yang dihentikan, jika ada.

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.

Dalam loop bersarang, statement break hanya mengakhiri perulangan terdalam yang berisinya, seperti yang ditunjukkan contoh berikut:

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

Saat Anda menggunakan statement switch di dalam perulangan, statement break di akhir bagian switch hanya mentransfer kontrol dari statement switch. Perulangan yang berisi statement switch tidak terpengaruh, seperti yang ditunjukkan contoh berikut:

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.

Pernyataan continue

Statement continue memulai perulangan baru dari enclosing terdekat statement iterasi (yaitu, for, foreach, while, atau loop do), seperti yang ditunjukkan contoh berikut:

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

Pernyataan return

Statement return mengakhiri eksekusi fungsi tempat fungsi tersebut muncul dan mengembalikan kontrol ke pemanggil.

Jika member fungsi tidak menghitung nilai, gunakan statement return tanpa expression, seperti yang ditunjukkan contoh berikut:

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

Seperti yang ditunjukkan oleh contoh sebelumnya, Anda secara khusus menggunakan statement return tanpa expression untuk mengakhiri member fungsi lebih awal. Jika member fungsi tidak berisi statement return, statement akan dihentikan setelah statement terakhirnya dijalankan.

Jika member fungsi tidak menghitung nilai, gunakan statement return tanpa expression, seperti yang ditunjukkan contoh berikut:

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;
}

Ketika statement return memiliki expression, expression tersebut harus secara implisit dapat dikonversi ke tipe pengembalian member fungsi kecuali jika async. Ekspresi yang async dikembalikan dari fungsi harus secara implisit dapat dikonversi ke argumen Task<TResult> jenis atau ValueTask<TResult>, mana pun yang merupakan jenis pengembalian fungsi. Jika tipe pengembalian pada sebuah fungsi async adalah Task atau ValueTask, Anda menggunakan statement return tanpa ekspresi.

Ref mengembalikan

Secara default, statement return mengembalikan nilai expression. Anda dapat mengembalikan referensi ke variabel. Nilai pengembalian referensi (atau pengembalian ref) adalah nilai yang dikembalikan metode dengan merujuk ke pemanggil. Artinya, pemanggil bisa memodifikasi nilai yang dikembalikan oleh metode, dan perubahan itu tercermin dalam status objek dalam metode yang disebut. Untuk melakukannya, gunakan return pernyataan dengan ref kata kunci, seperti yang ditunjukkan contoh berikut:

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.");
}

Nilai pengembalian referensi memungkinkan metode untuk mengembalikan referensi ke variabel, bukan nilai, kembali ke pemanggil. Pemanggil lalu dapat memilih untuk memperlakukan variabel yang dikembalikan seolah-olah dikembalikan dengan nilai atau dengan referensi. Pemanggil dapat membuat variabel baru yang merupakan referensi ke nilai yang dikembalikan, yang disebut lokal ref. Nilai pengembalian referensi berarti bahwa suatu metode mengembalikan referensi (atau alias) ke beberapa variabel. Cakupan variabel tersebut harus menyertakan metode. Masa pakai variabel itu harus melampaui kembalinya metode. Modifikasi nilai kembalian metode oleh pemanggil dibuat ke variabel yang dikembalikan oleh metode.

Menyatakan bahwa metode mengembalikan nilai pengembalian referensi menunjukkan bahwa metode mengembalikan alias ke variabel. Niat desain sering kali memanggil kode mengakses variabel tersebut melalui alias, termasuk untuk memodifikasinya. Metode yang dikembalikan berdasarkan referensi tidak boleh memiliki jenis voidpengembalian .

Agar pemanggil mengubah status objek, nilai pengembalian referensi harus disimpan ke variabel yang secara eksplisit didefinisikan sebagai variabel referensi.

Nilai ref yang dikembalikan adalah alias ke variabel lain dalam cakupan metode yang disebut. Anda dapat menginterpretasikan setiap penggunaan pengembalian ref sebagai menggunakan variabel aliasnya:

  • Saat Menetapkan nilainya, Anda menetapkan nilai ke variabel aliasnya.
  • Saat Anda membaca nilainya, Anda membaca nilai variabel aliasnya.
  • Jika Anda mengembalikannya dengan referensi, Anda mengembalikan alias ke variabel yang sama.
  • Jika Anda meneruskannya ke metode lain dengan referensi, Anda meneruskan referensi ke variabel aliasnya.
  • Ketika Anda membuat alias lokal ref, Anda membuat alias baru ke variabel yang sama.

Pengembalian ref harus berupa ref-safe-context ke metode panggilan. Itu berarti:

  • Nilai kembalian harus memiliki masa pakai yang melampaui eksekusi metode. Dengan kata lain, itu tidak boleh menjadi variabel lokal dalam metode yang mengembalikannya. Ini bisa berupa instans atau bidang statis kelas, atau dapat menjadi argumen yang diteruskan ke metode . Mencoba mengembalikan variabel lokal menghasilkan kesalahan kompilator CS8168, "Tidak dapat mengembalikan 'obj' lokal dengan referensi karena bukan lokal ref."
  • Nilai yang dikembalikan tidak boleh berupa literal null. Metode dengan pengembalian ref dapat mengembalikan alias ke variabel yang nilainya saat ini null adalah nilai (tidak terinstansiasi) atau jenis nilai nullable untuk jenis nilai.
  • Nilai yang dikembalikan tidak boleh berupa konstanta, anggota enumerasi, nilai pengembalian menurut nilai dari properti, atau metode atau classstruct.

Selain itu, nilai pengembalian referensi tidak diizinkan pada metode asinkron. Metode asinkron dapat kembali sebelum selesai dieksekusi, sementara nilai pengembaliannya masih belum diketahui.

Metode yang mengembalikan nilai pengembalian referensi harus:

  • Sertakan kata kunci ref di depan jenis pengembalian.
  • Setiap pernyataan pengembalian dalam isi metode menyertakan kata kunci ref di depan nama instans yang dikembalikan.

Contoh berikut menunjukkan metode yang memenuhi kondisi tersebut dan mengembalikan referensi ke objek Person bernama p:

public ref Person GetContactInformation(string fname, string lname)
{
    // ...method implementation...
    return ref p;
}

Berikut ini adalah contoh ref return yang lebih lengkap, yang menunjukkan tanda tangan metode dan badan metode.

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");
}

Metode yang dipanggil juga bisa mendeklarasikan nilai ref readonly yang dikembalikan sebagai untuk mengembalikan nilai menurut referensi, dan memberlakukan bahwa kode panggilan tidak dapat mengubah nilai yang dikembalikan. Metode panggilan dapat menghindari penyalinan nilai yang dikembalikan dengan menyimpan nilai dalam variabel referensi lokal ref readonly .

Contoh berikut ini mendefinisikan kelas Book yang memiliki dua bidang String, yaitu Title dan Author. Contoh ini juga mendefinisikan kelas BookCollection yang mencakup array privat dari objek Book. Objek buku individual dikembalikan dengan referensi dengan memanggil metode 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();
    }
}

Saat pemanggil menyimpan nilai yang dikembalikan oleh metode GetBookByTitle sebagai lokal ref, perubahan yang dilakukan pemanggil ke nilai pengembalian tercermin dalam objek BookCollection, seperti yang ditunjukkan contoh berikut.

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

Pernyataan goto

Statement mentransfer goto kontrol ke statement yang ditandai oleh label, seperti yang ditunjukkan contoh berikut:

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.

Seperti yang ditunjukkan oleh contoh sebelumnya, Anda dapat menggunakan statement goto untuk keluar dari loop bersarang.

Tip

Saat Anda bekerja dengan loop bersarang, pertimbangkan untuk melakukan refaktor loop terpisah ke dalam method terpisah. Itu dapat menyebabkan kode yang lebih sederhana dan lebih mudah dibaca tanpa statement goto.

Anda juga dapat menggunakan statement goto dalam switch statement untuk mentransfer kontrol ke bagian switch dengan label kasus konstanta, seperti yang ditunjukkan contoh berikut:

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;
    }
}

Dalam statement switch, Anda juga dapat menggunakan statement goto default; untuk mentransfer kontrol ke bagian switch dengan label default.

Jika label dengan nama yang diberikan tidak ada di anggota fungsi saat ini, atau jika goto pernyataan tidak berada dalam lingkup label, kesalahan waktu kompilasi terjadi. Artinya, Anda tidak dapat menggunakan goto pernyataan untuk mentransfer kontrol keluar dari anggota fungsi saat ini atau ke dalam cakupan berlapis apa pun.

Spesifikasi bahasa C#

Untuk informasi selengkapnya, lihat bagian berikut dari spesifikasi bahasa C#:

Lihat juga