Sebuah property terlihat seperti field bagi kode yang memakainya (order.Total, order.Total = 5), tetapi sebenarnya sepasang method: accessor get yang mengembalikan nilai dan accessor set yang menerima nilai. Lapisan perantara ini memungkinkan class memeriksa nilai, menghitungnya, atau menolak penulisan, tanpa mengubah cara pemanggil memakainya.
Field vs property
Field public memberikan akses langsung ke penyimpanan object. Siapa pun bisa memasukkan apa saja ke dalamnya:
public class Account
{
public decimal Balance; // any code can write -500 here
}
Property menaruh kode di antara pemanggil dan penyimpanannya. Berikut bentuk lengkap yang ditulis manual: sebuah backing field private plus property dengan kedua accessor. Di dalam set, kata kunci value adalah nilai yang sedang diberikan.
Output:
250
Rejected a negative balance
250
Selain untuk validasi, property penting karena sebagian besar ekosistem .NET bekerja dengan property dan mengabaikan field: interface bisa mendeklarasikan property tetapi tidak bisa mendeklarasikan field instance, data binding di WPF dan MAUI terhubung ke property, dan System.Text.Json secara default melakukan serialisasi pada property public dan melewati field.
Auto-property
Jika accessor-nya hanya akan membaca dan menulis field, biarkan compiler yang menuliskannya. { get; set; } adalah auto-implemented property: compiler membuatkan backing field tersembunyi untukmu.
Output:
Notebook: 9.99, 10 left
Bentuknya seperti field, jadi kenapa repot? Karena mengubah field public menjadi property di kemudian hari adalah breaking change bagi kode terkompilasi yang memakainya (dan bagi argumen ref dan out), sedangkan mengubah auto-property menjadi property lengkap dengan validasi tidak terlihat oleh pemanggilnya. Memulai dengan { get; set; } menjaga pilihan itu tetap terbuka tanpa biaya.
private set dan property get-only
Sebagian besar state sebaiknya bisa dibaca semua orang, tetapi hanya bisa diubah oleh object itu sendiri. Beri setter access modifier yang lebih sempit:
Output:
Ines: 2 items, total 15.75
Di sini ada tiga jenis read-only:
{ get; private set; }: class bisa mengubahnya kapan saja, kode dari luar tidak bisa.{ get; }(auto-property get-only, C# 6): hanya bisa diisi di constructor atau di initializer. Setelah object dibuat, tidak ada yang bisa mengubahnya, bahkan class itu sendiri. Begini cara membuat property yang immutable.=> expression(property terhitung): sama sekali tidak punya penyimpanan. Ekspresinya dijalankan setiap kali dibaca, jadiTotalselalu sesuai dengan isi list.
Property terhitung sebaiknya ringan dan tidak punya efek samping, karena pemanggil membaca property dengan santai, di dalam perulangan dan di debugger. Jika mendapatkan nilainya butuh kerja berat (query database, perhitungan besar), jadikan method seperti CalculateTotal() agar biayanya terlihat.
Accessor dengan expression body
Property lengkap yang accessor-nya satu baris bisa memakai => untuk setiap accessor:
private string title;
public string Title
{
get => title;
set => title = value?.Trim() ?? "";
}
public decimal Total => SumPrices(); adalah singkatan untuk property yang hanya punya getter; get => ... adalah ide yang sama di dalam property yang juga punya setter.
Logika getter dan setter: notifikasi dan nilai lazy
Karena accessor adalah method, ia bisa melakukan lebih dari sekadar menyimpan nilai. Dua pola yang umum: memicu notifikasi perubahan dari setter, dan menghitung nilai saat pertama kali dibaca lalu menyimpannya di cache.
Output:
(building summary)
Theme: light
Theme: light
Theme changed
(building summary)
Theme: dark
Changed adalah sebuah event, dan pola setter ini adalah bentuk implementasi INotifyPropertyChanged di WPF dan MAUI. nameof(Theme) menjaga string-nya tetap sesuai jika property itu diganti namanya.
Kesalahan rekursi tanpa akhir
Bug property yang paling umum adalah setter yang mengisi property itu sendiri, bukan backing field-nya:
public string Name
{
get { return Name; } // calls get again, forever
set { Name = value; } // calls set again, forever
}
Setiap accessor memanggil dirinya sendiri, dan program berhenti dengan StackOverflowException, yang tidak bisa ditangkap. Solusinya adalah membaca dan menulis field terpisah (name, huruf kecil), atau memakai auto-property. C# 14 menambahkan kata kunci field khusus untuk kasus ini: di dalam accessor, field merujuk ke backing field yang dibuat compiler, jadi set => field = value.Trim(); bisa berjalan tanpa mendeklarasikan field sendiri.
Accessor init (C# 9)
Property get-only memaksamu meneruskan setiap nilai lewat constructor. C# 9 menambahkan init, setter yang hanya diizinkan selama object dibuat: di constructor, atau di object initializer.
public class Product
{
public string Sku { get; init; }
public decimal Price { get; init; }
}
var p = new Product { Sku = "MUG-01", Price = 8.50m }; // fine: during creation
p.Price = 4m; // error CS8852: Init-only property or indexer 'Product.Price' can only be assigned
// in an object initializer, or on 'this' or 'base' in an instance constructor or an 'init' accessor
Hasilnya adalah object immutable dengan sintaks initializer, persis seperti yang dipakai record class untuk property posisionalnya. Untuk "mengubah" object seperti itu, buat object baru; record membuatnya cukup satu baris dengan with.
Di C# 7, padanan terdekatnya adalah property get-only plus parameter constructor:
public class Product
{
public string Sku { get; }
public decimal Price { get; }
public Product(string sku, decimal price) { Sku = sku; Price = price; }
}
Member required (C# 11)
Object initializer tidak bisa memaksa pemanggil mengisi apa pun: new Product { } tetap bisa dikompilasi meskipun Sku tidak boleh kosong. C# 11 menambahkan modifier required:
public class User
{
public required string Email { get; init; }
public string DisplayName { get; init; } = "";
}
var ok = new User { Email = "ana@example.com" };
var bad = new User { DisplayName = "Ana" }; // error CS9035: Required member 'User.Email'
// must be set in the object initializer or attribute constructor.
required bisa dipakai dengan set dan init. Constructor yang mengisi member required sendiri bisa menyatakannya dengan attribute [SetsRequiredMembers], sehingga pemanggil yang memakai constructor itu tidak diminta mengisinya lagi.
Kesalahan umum
- Rekursi di dalam accessor.
set { Name = value; }memanggil dirinya sendiri. Pakai backing field atau auto-property. - Getter yang berat atau punya efek samping. Pembaca mengira membaca property itu cepat dan aman diulang. Pakai method untuk pekerjaan berat.
- Field public "untuk sementara". Mengubah field menjadi property di kemudian hari merusak kompatibilitas biner, dan serializer mengabaikan field secara default. Mulailah dengan auto-property.
- Setter public di mana-mana.
{ get; set; }pada saldo atau status membuka jalan ke state yang tidak valid. Pakaiprivate set,init, atau get-only, dan ubah state lewat method. - Mengembalikan collection yang bisa diubah dari property get-only.
public List<string> Tags { get; }mencegah pemanggil mengganti list-nya, tetapi tidak mencegah mereka menambah isinya. KembalikanIReadOnlyList<string>jika collection itu tidak boleh diubah dari luar.
Pertanyaan yang sering diajukan
Apa arti { get; set; } di C#?
Itu mendeklarasikan auto-implemented property: compiler membuat field private tersembunyi, accessor get yang mengembalikannya, dan accessor set yang mengisinya. public string Name { get; set; } terlihat seperti field public bagi pemanggilnya, tetapi sebenarnya sepasang method, jadi nanti kamu bisa menambahkan validasi atau mengubahnya menjadi private set tanpa mengubah kode yang memakainya.
Apa perbedaan field dan property di C#?
Field adalah variabel yang disimpan di dalam object. Property adalah sepasang method (get dan set) yang dari luar terlihat seperti field. Property memungkinkan class memvalidasi nilai, menghitung hasil, atau membatasi penulisan, dan property-lah yang dipakai oleh data binding, serializer, dan interface. Data public sebaiknya dibuka lewat property; field biasanya tetap private.
Apa itu private set di C#?
public int Stock { get; private set; } membuat kode mana pun bisa membaca property itu, tetapi hanya kode di dalam class yang bisa mengubahnya. Dengan cara ini class membuka state yang dimilikinya, misalnya saldo atau jumlah, sambil menjaga semua perubahan tetap lewat method yang menegakkan aturannya.
Apa fungsi init di C#?
init (C# 9) adalah setter yang hanya berlaku selama object sedang dibuat: di constructor atau di object initializer. public string Sku { get; init; } mengizinkan new Product { Sku = "A-1" }, tetapi menolak product.Sku = "B-2" sesudahnya dengan error CS8852. Ini memberi object immutable sintaks initializer.
Apa itu required property di C#?
Property yang ditandai required (C# 11) wajib diisi oleh setiap object initializer yang membuat tipe itu; jika dilewatkan, terjadi error kompilasi (CS9035). Kata kunci ini cocok dipadukan dengan init: public required string Email { get; init; } wajib diisi saat dibuat dan tidak bisa diubah sesudahnya.