Property

Auto-property, aksesor get dan set, serta setter init-only.

Daftar isi

Topik ini membahas property, yaitu anggota kelas yang dibaca dan ditulis seperti field tetapi dijalankan sebagai kode. Materinya mencakup auto-property, penggunaan aksesor (accessor, metode pembaca dan penulis nilai di balik property) get dan set, serta setter init-only yang menutup perubahan setelah object selesai dikonstruksi. Setelah topik ini diselesaikan, papan data kelas dapat diekspos dengan aturan akses dan validasi yang terkendali.

Auto-property#

Property menjembatani dua kebutuhan yang saling bertentangan, yaitu sintaks pembacaan field yang ringkas dan kontrol penuh atas aksesnya. Bentuk paling ringkasnya adalah auto-property, yaitu property yang tubuh aksesor kosong sehingga kompilator membuat field penyangga (backing field) secara otomatis. Property seperti ini dideklarasikan dengan { get; set; } dan dipakai persis seperti field biasa.

csharp Program.cs
// Program: auto-property, property terhitung, dan pembaruan nilai melalui setter.
var buku = new Buku
{
    Kode = "B-1001",
    Judul = "Pengantar Statistika",
    Harga = 85000,
    Jumlah = 3
};

Console.WriteLine(buku.Judul);
Console.WriteLine(buku.Total);

buku.Harga = 92000;
Console.WriteLine(buku.Total);

class Buku
{
    public string Kode { get; init; } = "";
    public string Judul { get; set; } = "";
    public int Harga { get; set; }
    public int Jumlah { get; set; }

    public int Total => Harga * Jumlah;
}
text Keluaran
Pengantar Statistika
255000
276000

Property Harga dan Jumlah dibaca dan ditulis melalui sintaks field, tetapi setiap akses melewati aksesor yang dibuat kompilator. Inisialisator = "" pada dua property string mengisi nilai awal sehingga property tidak pernah bernilai null sebelum diisi. Nilai Total yang berubah dari 255000 menjadi 276000 menunjukkan bahwa penugasan buku.Harga = 92000; benar-benar mengubah data object melalui aksesor set.

Aksesor get dan set#

Aksesor get dijalankan ketika property dibaca, sedangkan aksesor set dijalankan ketika property ditulis dan menerima nilai barunya melalui kata kunci value. Bila logika tambahan diperlukan, bentuk auto-property tidak lagi cukup, sehingga field penyangga dideklarasikan sendiri dan kedua aksesor menuliskan logikanya secara eksplisit. Dari luar kelas, aksesnya tidak terbedakan dari pembacaan dan penulisan field biasa.

csharp Contoh: validasi pada aksesor set
var kategori = new Kategori();
kategori.Batas = 100;
Console.WriteLine(kategori.Batas);

try
{
    kategori.Batas = -5;
}
catch (ArgumentException e)
{
    Console.WriteLine($"Ditolak: {e.Message}");
}

class Kategori
{
    private int batas;

    public int Batas
    {
        get { return batas; }
        set
        {
            if (value < 0)
            {
                throw new ArgumentException("Batas tidak boleh negatif");
            }
            batas = value;
        }
    }
}
text Keluaran
100
Ditolak: Batas tidak boleh negatif

Penugasan yang sah diteruskan ke field batas, sedangkan penugasan -5 ditolak dengan melemparkan exception ArgumentException sebelum data object tercemar. Inilah keunggulan property atas field publik, yaitu aturan dapat ditegakkan pada satu tempat, dan seluruh penugasan dari bagian mana pun program otomatis melewatinya. Bentuk aksesor ini dipakai pula untuk konversi nilai atau pencatatan, sesuai kebutuhan kelasnya.

Validasi pada aksesor menjadikan property titik pemeriksaan tunggal. Setiap penugasan, baik dari metode kelas itu sendiri maupun dari pemanggil luar, melewati jalur yang sama, sehingga aturan tidak mudah terlewat ketika kode bertambah. Apabila pemeriksaan tidak diperlukan lagi, logikanya cukup dihapus dari satu tempat, dan seluruh pemanggil otomatis mengikuti perubahannya.

Akses kedua aksesor juga dapat dibedakan dengan menuliskan modifier pada salah satunya, misalnya public int Harga { get; private set; } yang terbaca dari mana pun tetapi hanya dapat ditulis dari dalam kelasnya. Pola ini cocok untuk data yang perubahannya harus melalui metode tertentu, karena setter tetap tersedia bagi kelasnya tanpa terbuka bagi pemanggil luar. Kombinasi lain yang lazim adalah protected set, yang membatasi penulisan pada kelas itu sendiri dan kelas turunannya.

Property hanya-baca dan terhitung#

Property yang hanya memiliki aksesor get bersifat hanya-baca dari luar kelas. Penugasannya hanya boleh terjadi di dalam konstruktor atau inisialisator object, sehingga cocok untuk data yang ditetapkan sekali saat object dibuat. Pembacaan dari luar tetap bekerja seperti biasa, sedangkan penugasan dari luar ditolak saat kompilasi.

csharp Contoh: property hanya-baca yang diisi konstruktor
var acara = new Acara("Rapat Koordinasi");
Console.WriteLine(acara.Nama);

class Acara
{
    public string Nama { get; }

    public Acara(string nama)
    {
        Nama = nama;
    }
}
text Keluaran
Rapat Koordinasi

Selain menyimpan data, property juga dapat menghitung nilai dari anggota lain. Bentuk public int Total => Harga * Jumlah; pada kelas Buku adalah property terhitung tanpa field penyangga, sehingga setiap pembacaan Total selalu mencerminkan Harga dan Jumlah terbaru. Karena tidak menyimpan apa pun, property semacam ini tidak memiliki aksesor set sama sekali, dan bentuk aksesor lengkapnya berupa get { return Harga * Jumlah; } yang hasilnya identik dengan bentuk ekspresinya.

Setter init-only#

Aksesor init menggantikan set untuk data yang boleh diisi hanya pada saat konstruksi. Property yang menggunakannya dapat ditugaskan di dalam inisialisator object atau konstruktor, tetapi ditolak setelahnya. Kombinasi { get; init; } menghasilkan data yang aman dibagikan karena tidak ada jalur untuk mengubahnya di tengah pemakaian.

csharp Contoh: penugasan ulang setter init-only ditolak
// tidak-dijalankan
buku.Kode = "B-2002";

Kompilator menolak penugasan tersebut dengan error CS8852: Init-only property or indexer 'Buku.Kode' can only be assigned in an object initializer. Property Kode pada kelas Buku memang menggunakan { get; init; }, sehingga satu-satunya peluang mengisinya adalah pemanggilan new Buku { ... } pada program di awal topik. Apabila nilainya memang harus berubah, perubahannya dinyatakan dengan membuat object baru, bukan dengan membuka aksesor set.

Kesalahan umum#

  • Menamai field penyangga sama dengan property-nya. Aksesor yang membaca property itu sendiri tanpa menyentuh field penyangga memanggil dirinya berulang-ulang dan berakhir dengan StackOverflowException. Beri field penyangga nama berbeda, misalnya batas untuk property Batas.
  • Menugaskan kembali property { get; init; }. Aksesor init menutup penugasan setelah konstruksi, sehingga muncul error CS8852. Gunakan ekspresi penyalinan dengan data yang diperbarui atau buat object baru, dan hindari membuka set hanya demi satu penugasan.
  • Meletakkan logika berat di dalam aksesor. Aksesor dijalankan setiap kali property disentuh, termasuk saat penelusuran (debugging) di debugger, sehingga logika berat menyulitkan pemahaman perilaku kode. Simpan logika berat di metode bernama yang jelas dan biarkan aksesor ringan.

Ringkasan#

  • Property dibaca dan ditulis seperti field tetapi dijalankan sebagai kode melalui aksesor get dan set.
  • Auto-property meminta kompilator membuat field penyangga, sedangkan aksesor lengkap memungkinkan validasi seperti penolakan nilai negatif.
  • Property hanya-baca { get; } diisi pada konstruksi, dan property terhitung tanpa penyangga selalu menghitung ulang dari anggota lain.
  • Aksesor init membatasi penugasan pada saat konstruksi saja, sehingga data menjadi tidak dapat diubah setelah object selesai dibuat.

Referensi#