Menu

C# Property'ler: get, set, Auto-Property, init ve required

C# property'leri nasıl çalışır: bir arka plan alanı üzerinde get ve set erişimcileri, auto-property'ler, private set ve yalnızca get içeren property'ler, hesaplanan property'ler, setter'larda doğrulama ve C# 9 ile 11'deki init ve required anahtar kelimeleri.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

Bir property onu kullanan koda bir alan gibi görünür (order.Total, order.Total = 5), ama aslında bir metot çiftidir: bir değer döndüren bir get erişimcisi ve bir değer alan bir set erişimcisi. Bu dolaylılık, bir sınıfın çağıranların onu kullanma biçimini değiştirmeden değerleri kontrol etmesine, hesaplamasına ya da yazmaları reddetmesine izin verir.

Alanlar ve property'ler

Public bir alan, nesnenin depolamasına doğrudan erişim verir. Herkes içine her şeyi koyabilir:

public class Account
{
    public decimal Balance;   // any code can write -500 here
}

Bir property çağıran ile depolama arasına kod koyar. İşte elle yazılmış tam biçim: private bir arka plan alanı (backing field) ve iki erişimcisi olan bir property. set içinde value anahtar kelimesi atanan değerdir.

Çıktı:

250
Rejected a negative balance
250

Doğrulamanın ötesinde property'ler önemlidir, çünkü .NET ekosisteminin çoğu onlarla çalışır ve alanları yok sayar: interface'ler property bildirebilir ama örnek alanları bildiremez, WPF ve MAUI'de data binding property'lere bağlanır ve System.Text.Json varsayılan olarak public property'leri serileştirir, alanları atlar.

Auto-property'ler

Erişimciler yalnızca alanı okuyup yazacaksa, onları derleyicinin yazmasına izin verin. { get; set; } otomatik uygulanan bir property'dir: derleyici gizli arka plan alanını sizin için üretir.

Çıktı:

Notebook: 9.99, 10 left

Bir alan gibi görünüyor, o halde neden uğraşmalı? Çünkü public bir alanı sonradan bir property'ye çevirmek, onu kullanan derlenmiş kod için (ve ref ile out argümanları için) kırıcı bir değişikliktir; bir auto-property'yi doğrulamalı tam bir property'ye çevirmek ise çağıranlar için görünmezdir. { get; set; } ile başlamak bu seçeneği bedavaya açık tutar.

private set ve yalnızca get içeren property'ler

Çoğu durum herkes tarafından okunabilir ve yalnızca nesnenin kendisi tarafından değiştirilebilir olmalıdır. Setter'a daha dar bir erişim belirleyici verin:

Çıktı:

Ines: 2 items, total 15.75

Burada üç tür salt okunurluk var:

  • { get; private set; }: sınıf onu her zaman değiştirebilir, dışarıdaki kod değiştiremez.
  • { get; } (yalnızca get içeren auto-property, C# 6): yalnızca bir constructor'da ya da bir başlatıcıda atanabilir. Nesne oluşturulduktan sonra kimse, sınıfın kendisi bile, onu değiştiremez. Değiştirilemez bir property böyle yapılır.
  • => expression (hesaplanan property): hiç depolama yoktur. İfade her okumada çalışır, bu yüzden Total listeyle her zaman günceldir.

Hesaplanan bir property ucuz ve yan etkisiz olmalıdır, çünkü çağıranlar property'leri döngülerde ve debugger'da gelişigüzel okur. Değeri almak gerçek bir iş gerektiriyorsa (bir veritabanı sorgusu, büyük bir hesaplama), maliyetin görünür olması için onu CalculateTotal() gibi bir metot yapın.

Expression-bodied erişimciler

Tek satırlık erişimcileri olan tam property'ler her erişimci için => kullanabilir:

private string title;

public string Title
{
    get => title;
    set => title = value?.Trim() ?? "";
}

public decimal Total => SumPrices(); yalnızca getter'ı olan bir property'nin kısaltmasıdır; get => ... ise bir setter'ı da olan bir property'nin içindeki aynı fikirdir.

Getter ve setter mantığı: bildirimler ve tembel değerler

Erişimciler metot olduğu için bir değeri saklamaktan fazlasını yapabilir. İki yaygın kalıp: setter'dan bir değişiklik bildirimi tetiklemek ve bir değeri ilk okumada hesaplayıp önbelleğe almak.

Çıktı:

(building summary)
Theme: light
Theme: light
Theme changed
(building summary)
Theme: dark

Changed bir event'tir ve setter kalıbı WPF ve MAUI'deki INotifyPropertyChanged uygulamalarının görünümüdür. nameof(Theme) property yeniden adlandırılırsa string'i senkron tutar.

Sonsuz özyineleme hatası

En yaygın property hatası, arka plan alanı yerine property'nin kendisine atama yapan bir setter'dır:

public string Name
{
    get { return Name; }        // calls get again, forever
    set { Name = value; }       // calls set again, forever
}

Her erişimci kendini çağırır ve program yakalanamayan bir StackOverflowException ile ölür. Çözüm ayrı bir alanı (name, küçük harf) okuyup yazmak ya da bir auto-property kullanmaktır. C# 14 tam olarak bu durum için field anahtar kelimesini ekler: bir erişimcinin içinde field derleyicinin ürettiği arka plan alanına başvurur, bu yüzden set => field = value.Trim(); bir alan bildirmeden çalışır.

init erişimcileri (C# 9)

Yalnızca get içeren bir property her değeri bir constructor'dan geçirmeye zorlar. C# 9, yalnızca nesne oluşturulurken izin verilen bir setter olan init'i ekledi: bir constructor'da ya da bir nesne başlatıcıda.

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

Sonuç, başlatıcı sözdizimine sahip değiştirilemez bir nesnedir; record sınıflarının konumsal property'leri için kullandığı şey tam olarak budur. Böyle bir nesneyi "değiştirmek" için yeni bir tane oluşturun; record'lar bunu with ile tek satırlık yapar.

C# 7'de en yakın karşılık, yalnızca get içeren bir property ve bir constructor parametresidir:

public class Product
{
    public string Sku { get; }
    public decimal Price { get; }
    public Product(string sku, decimal price) { Sku = sku; Price = price; }
}

required üyeler (C# 11)

Bir nesne başlatıcı çağıranları hiçbir şeyi ayarlamaya zorlayamaz: Sku asla boş olmaması gerektiği halde new Product { } derlenir. C# 11 required belirleyicisini ekledi:

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, set ve init ile çalışır. Required üyeleri kendisi ayarlayan bir constructor bunu [SetsRequiredMembers] özniteliğiyle söyleyebilir; böylece o constructor'ı kullanan çağıranlardan onları yeniden ayarlamaları istenmez.

Yaygın hatalar

  • Bir erişimcide özyineleme. set { Name = value; } kendini çağırır. Bir arka plan alanı ya da bir auto-property kullanın.
  • Pahalı ya da yan etkili getter'lar. Okuyucular bir property okumasının hızlı ve tekrarlanması güvenli olmasını bekler. İş için bir metot kullanın.
  • "Şimdilik" public alanlar. Bir alanı sonradan bir property'ye çevirmek ikili uyumluluğu bozar ve serializer'lar varsayılan olarak alanları yok sayar. Bir auto-property ile başlayın.
  • Her şeyde public setter'lar. Bir bakiye ya da bir durum üzerinde { get; set; } geçersiz durumlara davetiye çıkarır. private set, init ya da yalnızca get kullanın ve durumu metotlar üzerinden değiştirin.
  • Yalnızca get içeren bir property'den değiştirilebilir bir koleksiyon döndürmek. public List<string> Tags { get; } çağıranların listeyi değiştirmesini engeller, ona ekleme yapmasını değil. Koleksiyon dışarıdan değişmemeliyse IReadOnlyList<string> döndürün.

Sıkça Sorulan Sorular

C#'ta { get; set; } ne anlama gelir?

Otomatik uygulanan bir property bildirir: derleyici gizli bir private alan, onu döndüren bir get erişimcisi ve ona atayan bir set erişimcisi oluşturur. public string Name { get; set; } çağıranlar için public bir alan gibi davranır, ama bir metot çiftidir; bu yüzden onu kullanan kodu değiştirmeden daha sonra doğrulama ekleyebilir ya da private set'e çevirebilirsiniz.

C#'ta alan (field) ile property arasındaki fark nedir?

Alan, nesnede saklanan bir değişkendir. Property ise dışarıdan bir alan gibi görünen bir metot çiftidir (get ve set). Property'ler bir sınıfın değerleri doğrulamasını, sonuçları hesaplamasını ya da yazmayı kısıtlamasını sağlar ve data binding, serializer'lar ve interface'ler onlarla çalışır. Public veri property olarak dışa açılmalıdır; alanlar genellikle private kalır.

C#'ta private set nedir?

public int Stock { get; private set; } her kodun property'yi okumasına ama yalnızca sınıfın içindeki kodun onu değiştirmesine izin verir. Bir sınıfın sahip olduğu durumu, örneğin bir bakiyeyi ya da bir sayıyı, tüm değişiklikleri kuralları uygulayan metotların arkasında tutarak dışa açmasının yolu budur.

C#'ta init ne işe yarar?

init (C# 9), yalnızca nesne oluşturulurken çalışan bir setter'dır: bir constructor'da ya da bir nesne başlatıcıda. public string Sku { get; init; } new Product { Sku = "A-1" }'e izin verir ama sonradan product.Sku = "B-2"'yi CS8852 hatasıyla reddeder. Değiştirilemez nesnelere başlatıcı sözdizimi kazandırır.

C#'ta required property nedir?

required (C# 11) işaretli bir property, tipi oluşturan her nesne başlatıcı tarafından ayarlanmalıdır; onu atlamak bir derleme hatasıdır (CS9035). init ile iyi birleşir: public required string Email { get; init; } oluşturulurken verilmek zorundadır ve sonradan değişemez.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA