Topik ini membahas primary constructor, yaitu daftar parameter yang ditulis langsung pada nama kelas atau struct, dan untuk keduanya diperkenalkan pada C# 12. Fitur ini menghilangkan penulisan berulang (boilerplate) konstruktor yang hanya menyalin parameter ke dalam field, sehingga kelas kecil pemegang data dapat dideklarasikan dalam beberapa baris. Setelah topik ini diselesaikan, class dan struct dengan primary constructor dapat ditulis, perilaku penangkapan parameternya dipahami, dan batasan yang menyertainya terbaca dari pesan error kompilator.
Deklarasi class dengan primary constructor#
Primary constructor diletakkan tepat setelah nama tipe, sebelum kurung kurawal tubuh kelas. Parameter di dalamnya dapat digunakan oleh seluruh anggota kelas, sehingga penyalinan manual ke field tidak lagi diperlukan untuk kelas yang sederhana. Program berikut memakai tiga tipe sekaligus, yaitu kelas pengonversi suhu, struct titik, dan kelas tiket antrean loket, agar pola penggunaannya terlihat pada class dan struct.
// Program: primary constructor pada class dan struct.
var konversi = new KonversiSuhu(25.0);
Console.WriteLine($"{konversi.Celsius} C = {konversi.Fahrenheit} F");
var titik = new Titik(2, 3);
Console.WriteLine($"({titik.X}, {titik.Y})");
var tiket = new TiketLoket("D-14");
Console.WriteLine($"{tiket.Kode}: sisa antrean {tiket.SisaAntrean}");
class KonversiSuhu(double celsius)
{
public double Celsius => celsius;
public double Fahrenheit => celsius * 9 / 5 + 32;
}
struct Titik(int x, int y)
{
public int X => x;
public int Y => y;
}
class TiketLoket(string kode)
{
public string Kode => kode;
public int SisaAntrean { get; set; } = 12;
}25 C = 77 F
(2, 3)
D-14: sisa antrean 12Kelas KonversiSuhu membaca parameter celsius dari dua property-nya, sedangkan TiketLoket memperlihatkan paduan yang lebih nyata, yaitu parameter kode yang dibaca property Kode dan property biasa SisaAntrean dengan inisialisator = 12. Primary constructor tidak menggantikan anggota lain, melainkan menyediakan sumber nilai awal yang dapat dipakai bersama property, field, dan metode biasa. Record posisional seperti record Titik(int X, int Y); sebenarnya sudah memakai bentuk ini sejak C# 9, sehingga C# 12 memperluas ketersediaannya ke class dan struct biasa.
Parameter yang ditangkap menjadi field#
Kompilator memeriksa letak penggunaan setiap parameter untuk menentukan perlakuannya. Parameter yang hanya digunakan pada tempat yang memang legal bagi parameter, misalnya di dalam inisialisator field, tidak disimpan sama sekali dan hidup hanya selama konstruksi berlangsung. Parameter yang dibaca oleh anggota instance seperti property Celsius ditangkap (capture) ke dalam field tersembunyi yang dibuat otomatis, sehingga nilainya tersedia sepanjang hidup object. Karena itulah kelas KonversiSuhu dapat membaca celsius dari dua property berbeda tanpa deklarasi field manual.
Sisi penting dari mekanisme ini adalah parameter tidak pernah menjadi anggota kelas. Nama seperti celsius tidak terlihat dari luar, tidak muncul pada penelusuran (debugging) di debugger, dan tidak tercantum sebagai anggota deklarasinya. Kode di luar kelas hanya dapat membaca nilainya melalui property yang disediakan, sebagaimana Celsius pada program di atas.
// tidak-dijalankan
Console.WriteLine(konversi.celsius); // menghasilkan error CS1061Kompilator melaporkan error CS1061: 'KonversiSuhu' does not contain a definition for 'celsius'. Perbaikannya adalah mengekspos property publik yang membaca parameter, sebagaimana dilakukan program di awal topik. Konvensi penamaannya mengikuti parameter metode biasa, yaitu huruf kecil untuk parameter seperti celsius dan huruf kapital untuk anggota publik seperti Celsius.
Satu batasan lain menyertai deklarasi ini. Kelas yang memiliki primary constructor tidak boleh lagi memiliki konstruktor sekunder tanpa perantai, karena semua jalan konstruksi wajib melewati primary constructor.
// tidak-dijalankan
// Di dalam kelas KonversiSuhu, deklarasi berikut menghasilkan error CS8862
public KonversiSuhu() { }Kompilator melaporkan error CS8862: A constructor declared in a type with parameter list must have 'this' constructor initializer. Perbaikannya adalah merantai konstruktor sekunder ke primary constructor, misalnya public KonversiSuhu() : this(0.0) { }, sehingga nilai parameternya selalu disediakan.
Struct dengan primary constructor#
Struct menerima bentuk yang sama, dan Titik pada program di atas menunjukkan parameternya dibaca dua property. Aturan penangkapan parameter pada struct sama dengan kelas, yaitu parameter yang dibaca anggota instance disimpan pada field tersembunyi. Struct tetap dapat dibuat tanpa melalui konstruktor, misalnya melalui default(Titik), dan pembuatan semacam itu mengisi seluruh field dengan nilai nol sehingga property X dan Y membaca 0. Karena itu anggota struct tidak boleh mengandalkan asumsi bahwa konstruktornya selalu dijalankan.
Nilai parameter boleh diberi nilai bawaan (default value), sehingga new Titik() menjadi sah apabila deklarasinya struct Titik(int x = 0, int y = 0). Bentuk ini menutup celah konstruksi tanpa argumen tanpa perlu menulis konstruktor tambahan. Untuk kelas, nilai bawaan yang sama berlaku dan membuat daftar argumen pemanggilan lebih lentur pada kelas yang parameternya memang lazim diisi nilai standar.
Kesalahan umum#
- Memperlakukan parameter sebagai anggota kelas. Akses seperti
konversi.celsiusdari luar kelas menghasilkan CS1061 karena parameter tidak pernah dideklarasikan sebagai anggota. Sediakan property atau metode yang membaca parameter, kemudian arahkan pemakaian ke anggota tersebut. - Menambahkan konstruktor sekunder tanpa perantai. Deklarasi
public KonversiSuhu() { }pada tipe yang memiliki primary constructor ditolak dengan CS8862. Rantai konstruktor sekunder melaluithis(...)agar setiap konstruksi melewati primary constructor. - Mengira parameter selalu disimpan. Parameter yang hanya dipakai di dalam inisialisator field tidak tersedia setelah konstruksi, sehingga anggota yang membutuhkan nilainya nanti tidak dapat membacanya. Simpan nilai pada field atau property sendiri apabila nilainya diperlukan sepanjang hidup object.
Ringkasan#
- Primary constructor dari C# 12 menaruh daftar parameter langsung pada nama class atau struct, dan parameternya dapat dibaca oleh seluruh anggota.
- Parameter yang dibaca anggota instance ditangkap ke field tersembunyi, sedangkan parameter yang hanya dipakai saat konstruksi tidak disimpan dan bukan anggota kelas.
- Konstruktor sekunder pada tipe dengan primary constructor wajib merantai
this(...), dan pelanggarannya ditolak dengan error CS8862. - Record posisional sudah memakai bentuk ini sejak C# 9, sedangkan C# 12 memperluasnya ke class dan struct biasa.
Referensi#
- What’s new in C# 12 — Microsoft Learn — Pengumuman C# 12 yang memperkenalkan primary constructor untuk class dan struct.
- Instance constructors — Microsoft Learn
— Panduan konstruktor instance yang memuat aturan primary constructor dan perantai
this(...). - Create concise classes with primary constructors — Microsoft Learn — Tutorial resmi perilaku penangkapan parameter primary constructor.