init dan required

Pola inisialisasi yang dipaksakan pada property.

Daftar isi

Topik ini membahas dua fitur yang memaksakan pola inisialisasi pada property, yaitu aksesor init yang diperkenalkan pada C# 9 dan kata kunci required yang diperkenalkan pada C# 11. Keduanya memindahkan pekerjaan mengisi data ke saat object dibuat, sehingga kelas yang sudah selesai dikonstruksi dijamin memuat nilai yang bermakna. Setelah topik ini diselesaikan, property init-only dan anggota required dapat dideklarasikan, penolakan kompilator terhadap pelanggarannya dapat dibaca, dan pilihan di antara keduanya dapat ditentukan secara sadar.

Aksesor init pada property#

Aksesor init menggantikan set untuk property yang boleh diisi hanya selama object sedang dibuat. Penugasan yang sah terbatas pada inisialisator object (object initializer), yaitu daftar { ... } setelah pemanggilan new, serta tubuh konstruktor dan aksesor init itu sendiri. Setelah fase konstruksi berakhir, tidak ada jalur kode apa pun yang dapat mengubah nilainya. Sifat ini membuat data yang sudah dikonstruksi aman dibagikan ke bagian program lain karena tidak ada anggota yang dapat menyuntingnya di tengah pemakaian.

Program berikut memakai kedua fitur tersebut pada kelas Catatan milik aplikasi catatan pribadi. Property Judul diberi required, sedangkan property Penulis cukup diisi melalui aksesor init dengan nilai awal bawaan.

csharp Program.cs
// Program: property init-only dan required pada kelas Catatan.
var catatan = new Catatan
{
    Judul = "Belanja mingguan",
    Penulis = "Dewi"
};

Console.WriteLine($"{catatan.Judul} oleh {catatan.Penulis}");

class Catatan
{
    public required string Judul { get; init; }
    public string Penulis { get; init; } = "Tanpa nama";
}
text Keluaran
Belanja mingguan oleh Dewi

Property Judul dideklarasikan dengan required, sedangkan Penulis mengandalkan inisialisator = "Tanpa nama". Inisialisator property dijalankan lebih dahulu, kemudian inisialisator object menimpanya bila penyebutnya ada, sehingga object tanpa Penulis tetap memuat teks yang layak ditampilkan dan tidak pernah bernilai null. Pola ini menggantikan kebiasaan menandai property sebagai nullable hanya demi menandai “belum diisi”, karena nilai awal yang bermakna dapat ditulis langsung pada deklarasinya.

Kata kunci required#

Kata kunci required menandai property atau field yang wajib diisi oleh setiap pembuat object. Pemeriksaannya dilakukan oleh kompilator (compiler), program yang menerjemahkan kode sumber menjadi program yang dapat dieksekusi, sehingga kelalaian mengisi data terlihat sebelum program sempat dijalankan. Anggota required paling sering dipadukan dengan aksesor init, tetapi paduan dengan aksesor set juga sah. Apabila pembuat object tidak menyebut anggota yang ditandai, kompilator menolak programnya dengan error CS9035.

csharp Contoh: object tanpa property required ditolak kompilator
// tidak-dijalankan
var arsip = new Catatan();

Kompilator melaporkan error CS9035: Required member 'Catatan.Judul' must be set in the object initializer or attribute constructor. Perbaikannya adalah menyebut Judul di dalam inisialisator object, sebagaimana program di awal topik. Nilai awal yang ditulis pada deklarasi property tidak mengecualikan aturan ini. Property Judul yang diberi inisialisator = "" tetap wajib disebut oleh setiap pembuat object, karena kata kunci required menuntut kehadiran nilai pada setiap konstruksi.

Konstruktor kelas dapat mengambil alih tuntutan tersebut apabila seluruh anggota required diisinya di dalam tubuh konstruktor dan konstruktornya diberi atribut [SetsRequiredMembers] dari namespace System.Diagnostics.CodeAnalysis. Pemanggil konstruktor tersebut kemudian bebas menulis inisialisator atau tidak sama sekali. Atribut ini menyatakan tanggung jawab pengisian secara eksplisit, sehingga aturan tetap terjaga tanpa menambah beban pada setiap pemanggilan new.

Penugasan setelah konstruksi ditolak#

Property yang menggunakan aksesor init berperilaku seperti field readonly setelah object selesai dibuat. Penugasan dari metode biasa ditolak meskipun dilakukan dari dalam kelasnya sendiri, karena batasannya melekat pada aksesor dan bukan pada tempat kode ditulis. Penerima data tersebut pun tidak perlu menyalin nilainya demi perlindungan, karena tidak ada pemutakhir yang dapat menyusup di tengah pemakaian.

csharp Contoh: penugasan ulang property init-only ditolak
// tidak-dijalankan
catatan.Judul = "Belanja mingguan berikutnya";

Kompilator melaporkan error CS8852: Init-only property or indexer 'Catatan.Judul' can only be assigned in an object initializer, or on 'this' or 'base' in an instance constructor or an 'init' accessor. Pesan tersebut menegaskan kedua tempat penugasan yang sah. Apabila nilainya memang perlu berubah, perubahan dinyatakan dengan membuat object baru yang menyalin data lama lalu mengganti bagian yang berbeda, misalnya melalui ekspresi with pada record. Pola ini membuat setiap perubahan data menghasilkan object yang baru, sehingga titik perubahannya selalu terlihat jelas di dalam kode.

Memilih antara set, init, dan required#

Ketiga bentuk property melayani kebutuhan yang berbeda, dan pilihannya paling mudah dinyatakan dalam tabel.

Bentuk propertyKapan boleh diisiCocok untuk
{ get; set; }kapan saja selama object hidupdata yang memang berubah, misalnya sisa antrean
{ get; init; }hanya saat konstruksidata tetap setelah dibuat, misalnya tanggal catatan
required dengan { get; init; }wajib diisi saat konstruksidata yang tidak boleh kosong, misalnya judul

Property { get; set; } tetap menjadi pilihan untuk data yang sejak awal dirancang berubah. Aksesor init dipakai ketika nilai perlu ditetapkan sekali lalu dijaga, dan pemakaiannya paling nyaman bersama inisialisator object karena daftar pengisiannya terbaca seperti daftar data. required ditambahkan ketika object tanpa nilai tertentu dianggap tidak sah, sehingga pembuat object yang lupa berhenti di tahap kompilasi dan tidak pernah menghasilkan object setengah jadi. Pilihan ini juga mendokumentasikan niat desain pada tempatnya, karena bentuk deklarasi sudah memuat janji tentang masa hidup data tanpa perlu membaca isi kelasnya.

Kesalahan umum#

  • Mengira inisialisator property mengecualikan required. Inisialisator = "" pada property required tidak membebaskan pembuat object, sehingga new Catatan() tetap ditolak dengan CS9035. Isi anggota required di setiap inisialisator object, atau pindahkan tanggung jawabnya ke konstruktor bertanda [SetsRequiredMembers].
  • Mengisi property init-only dari metode biasa. Penugasan tersebut menghasilkan CS8852 meskipun ditulis di dalam kelasnya sendiri, karena aksesor init menutup penugasan setelah konstruksi. Nyatakan perubahannya dengan object baru, atau gunakan aksesor set bila data memang harus berubah.
  • Menandai semua property dengan required. Tuntutan pengisian yang berlaku untuk data opsional membuat setiap pembuat object menulis nilai kosong tanpa makna. Gunakan required hanya untuk data yang ketiadaannya membuat object tidak sah.

Ringkasan#

  • Aksesor init dari C# 9 membatasi pengisian property pada fase konstruksi, sehingga data object tidak dapat berubah setelah dibuat.
  • Kata kunci required dari C# 11 menuntut setiap pembuat object mengisi anggota yang ditandai, dan kelalaian ditolak dengan error CS9035.
  • Penugasan ulang property init-only menghasilkan error CS8852, dan perubahan dinyatakan dengan object baru yang menyalin data lama.
  • Pilihan bentuk property mengikuti masa hidup datanya, yaitu set untuk data yang berubah, init untuk data tetap, dan required untuk data wajib.

Referensi#