tertutup (Referensi C#)

Mulai dari C# 15, Anda dapat menerapkan closed pengubah ke kelas untuk mendeklarasikan hierarki tertutup. Anda hanya dapat memperoleh subjenis langsung dari kelas tertutup dalam assembly yang mendeklarasikan. Karena set turunan langsung diperbaiki, switch ekspresi yang menangani setiap turunan langsung menghabiskan jenis dasar tertutup dan tidak memerlukan lengan default.

// Assembly 1
public closed record class JobStatus;
public record class Queued : JobStatus;
public record class Running(int PercentComplete) : JobStatus;
public record class Completed(TimeSpan Elapsed) : JobStatus;
public record class Failed(string Error) : JobStatus;

// Assembly 2
public record class Paused : JobStatus; // Error: 'JobStatus' is a closed class

Pembatasan rakitan yang sama hanya berlaku untuk turunan langsung dari kelas tertutup. Kelas yang berasal dari kelas tertutup tidak ditutup sendiri kecuali Anda juga menandainya closed. Karena Failed dalam contoh sebelumnya adalah catatan biasa, assembly lain dapat berasal darinya:

// Assembly 2
public record class RetryableFailed(string Error, int Attempts) : Failed(Error); // OK: 'Failed' isn't sealed or closed

Jika Anda ingin mencegah derivasi Failed juga, nyatakan sebagai sealed atau closed.

Referensi bahasa C# mendokumentasikan versi bahasa C# yang paling baru dirilis. Ini juga berisi dokumentasi awal untuk fitur dalam pratinjau publik untuk rilis bahasa yang akan datang.

Dokumentasi mengidentifikasi fitur apa pun yang pertama kali diperkenalkan dalam tiga versi terakhir bahasa atau dalam pratinjau publik saat ini.

Tip

Untuk menemukan kapan fitur pertama kali diperkenalkan di C#, lihat artikel tentang riwayat versi bahasa C#.

Note

closed adalah kata kunci kontekstual. Ini memiliki arti khusus hanya ketika muncul sebagai pengubah pada deklarasi kelas. Anda dapat terus menggunakan closed sebagai pengidentifikasi dalam konteks lain. Jika Anda perlu menggunakan closed sebagai pengidentifikasi dalam posisi di mana pengubah juga akan valid, awali dengan @ (misalnya, @closed) untuk memberi tahu pengkompilasi untuk memperlakukannya sebagai pengidentifikasi daripada pengubah.

Aturan deklarasi

Pengubah closed adalah pengubah kelas:

  • Kelas closed secara abstractimplisit . Anda tidak dapat menggabungkan closed dengan sealed, static, atau pengubah eksplisit abstract .
  • Anda harus mendeklarasikan subjenis langsung dari kelas tertutup dalam rakitan dan modul yang sama dengan kelas dasar tertutup.
  • Kelas yang berasal dari kelas tertutup tidak ditutup dengan sendirinya. Terapkan pengubah closed lagi jika Anda ingin kelas turunan juga ditutup.

Jika kelas generik secara langsung berasal dari closed kelas , setiap parameter jenis pada kelas turunan harus digunakan dalam spesifikasi kelas dasar. Aturan ini bukan tentang pengubah itu closed sendiri: jenis konstruksi tertutup adalah jenis generik yang argumen jenisnya sepenuhnya ditentukan (seperti Tree<int>), dibandingkan dengan jenis terbuka seperti Tree<T>. Aturan ini memastikan bahwa setiap jenis kelas dasar yang dibangun tertutup memiliki tepat satu jenis konstruksi tertutup yang sesuai di antara turunan langsungnya, sehingga pengkompilasi dapat beralasan tentang kelelahan.

public closed record class Tree<T>;

public record class Leaf<T>(T Value) : Tree<T>;                       // OK: 'T' appears in the base class
public record class Branch<T>(Tree<T> Left, Tree<T> Right) : Tree<T>; // OK: 'T' appears in the base class
public record class Constant<U>(U Value) : Tree<int> { } // Error: 'U' isn't used in the base class

Ekspresi sakelar lengkap

switch Saat ekspresi menangani setiap turunan langsung dari kelas tertutup, pengkompilasi mempertimbangkan sakelar lengkap dan tidak menghasilkan peringatan non-kelelahan:

public static string Describe(JobStatus status) => status switch
{
    Queued => "waiting to start",
    Running(var percent) => $"{percent}% complete",
    Completed(var elapsed) => $"finished in {elapsed.TotalSeconds:F1}s",
    Failed(var error) => $"failed: {error}",
    // No warning: every direct descendant of 'JobStatus' is handled.
};

Ketika ekspresi tata kelola pengalihan dapat diubah ke null, null menjadi nilai lain yang mungkin harus ditangani oleh sakelar. Switch over JobStatus? hanya lengkap ketika juga mencakup null:

public static string DescribeOrUnknown(JobStatus? status) => status switch
{
    null => "unknown",
    Queued => "waiting to start",
    Running(var percent) => $"{percent}% complete",
    Completed(var elapsed) => $"finished in {elapsed.TotalSeconds:F1}s",
    Failed(var error) => $"failed: {error}",
    // No warning: every direct descendant of 'JobStatus' is handled, and null is handled.
};

Jika Anda menghilangkan null lengan, pengkompilasi memperingatkan bahwa pola null tidak ditangani. Aturan yang sama berlaku apakah jenis tertutup adalah kelas atau struct yang diangkat ke jenis nullable.

Untuk informasi selengkapnya tentang bagaimana kompilator menentukan kelelahan, termasuk bagaimana hierarki tertutup berinteraksi dengan batasan dan aksesibilitas generik, lihat Pola hierarki tertutup.

Jenis parameter dibatasi untuk jenis tertutup

Parameter jenis yang dibatasi ke kelas tertutup diperlakukan sebagai kelas tertutup tersebut untuk pemeriksaan kelelahan. switch Ekspresi yang nilai tata kelolanya memiliki parameter jenis seperti itu lengkap ketika menangani setiap turunan langsung dari batasan tertutup:

public static string DescribeJob<X>(X status) where X : JobStatus => status switch
{
    Queued => "waiting to start",
    Running(var percent) => $"{percent}% complete",
    Completed(var elapsed) => $"finished in {elapsed.TotalSeconds:F1}s",
    Failed(var error) => $"failed: {error}",
    // No warning: 'X' is constrained to a closed type, so its direct descendants exhaust the switch.
};

Aturan ini menerapkan apakah parameter jenis muncul pada metode atau pada jenis yang berisi.

Spesifikasi bahasa C#

Untuk informasi selengkapnya, lihat spesifikasi fitur Hierarki tertutup.

Baca juga