Record sudah lama memakai primary constructor: daftar parameter yang ditulis di depan nama tipe. C# 12 memperluas fasilitas ini ke class dan struct biasa. Parameter tersebut tersedia di seluruh badan tipe, dan compiler menentukan sendiri kapan parameter cukup disalin dan kapan harus ditangkap menjadi field. Bab ini membedah kedua perilaku itu beserta pewarisannya.

Parameter yang Ditangkap #

Aturan intinya dua. Pertama, parameter yang hanya dipakai untuk mengisi property atau field akan disalin pada saat konstruksi, dan compiler tidak menyimpan apa pun setelahnya. Kedua, parameter yang dibaca di dalam method atau property expression ditangkap: compiler membentuk field privat agar nilai tetap hidup selama instance ada. Perbedaan ini membedakannya dari record, yang mengubah setiap parameter primary constructor menjadi property publik.

Contoh: Kartu Parkir dan Pewarisan #

csharp
class KartuParkir(string plat, int lantai)
{
    public string Plat { get; } = plat;
    public int Lantai { get; private set; } = lantai;

    public string Ringkasan()
    {
        return $"{plat} | lantai {lantai}";
    }
}

class Kendaraan(string plat)
{
    public string Plat => plat;
}

class Mobil : Kendaraan
{
    public int Roda { get; }

    public Mobil(string plat, int roda) : base(plat)
    {
        Roda = roda;
    }
}

class Sepeda(string plat, string jenis) : Kendaraan(plat)
{
    public string Jenis => jenis;
}

KartuParkir kartu = new KartuParkir("B 1234 XYZ", 3);
Console.WriteLine($"{kartu.Plat} | {kartu.Lantai}");
Console.WriteLine(kartu.Ringkasan());

Mobil mobil = new Mobil("D 5678 ABC", 4);
Sepeda sepeda = new Sepeda("F 9012 KLM", "Listrik");
Console.WriteLine($"{mobil.Plat} {mobil.Roda}");
Console.WriteLine($"{sepeda.Plat} {sepeda.Jenis}");

Output yang Dihasilkan:

text
B 1234 XYZ | 3
B 1234 XYZ | lantai 3
D 5678 ABC 4
F 9012 KLM Listrik

Mari kita bedah baris demi baris:

  1. KartuParkir(string plat, int lantai): parameter ditulis di depan nama class; kedua property diisi langsung dari parameter tanpa constructor eksplisit.
  2. Ringkasan(): method membaca plat dan lantai langsung, sehingga compiler menangkap keduanya sebagai field privat.
  3. Mobil : Kendaraan: class turunan boleh menulis constructor biasa dan meneruskan data lewat base(plat); gaya lama dan baru dapat dicampur.
  4. Sepeda(string plat, string jenis) : Kendaraan(plat): primary constructor turunan meneruskan plat ke primary constructor induk, lalu memakai jenis untuk property miliknya.
  5. sepeda.Plat: property Plat milik induk bekerja normal, karena Kendaraan menerima nilainya dari primary constructor Sepeda.

Kapan Dipakai #

Primary constructor meringkas tipe kecil yang parameternya langsung menetap ke property atau field, termasuk validasi sederhana lewat initializer seperti = lantai > 0 ? lantai : 1. Untuk tipe dengan logika konstruksi yang panjang, constructor eksplisit masih lebih terbaca. Perlu diingat, parameter primary constructor bukan property publik; kode luar tidak dapat membacanya.