Özel değişken vs özellik?


41

Bir sınıf içindeki değişkene bir değer verirken çoğu zaman iki seçenek sunulur:

private string myValue;
public string MyValue
{
   get { return myValue; }
   set { myValue = value; }
}

Sınıflarımızın içindeki değişkenlere nasıl değer atamamız gerektiğini belirleyen bir kural var mı? Örneğin, aynı sınıf içinde bir yönteme sahipsem, özelliğini kullanarak veya özel değişkeni kullanarak atamalı mıyım? Her iki şekilde de yapıldığını gördüm, bu yüzden bunun bir seçim mi yoksa performansın bir faktör mü (küçük, muhtemelen) olup olmadığını merak ediyordum.

Yanıtlar:


23

Bir adım daha öteye götürür ve 3 duruma getirirdim. Her birinde farklılıklar olsa da, C # programlamada çoğu zaman kullandığım kurallar budur.

2 ve 3 durumunda, her zaman Mülkiyet Erişicisine gidin (alan değişkeni değil). Ve 1 durumunda, bu seçimi yapmak zorunda kalmaktan bile kurtuldunuz.

1.) Taşınmaz mal (kurucuya devredilmiş veya inşaat zamanında yaratılmış). Bu durumda, salt okunur özelliğe sahip bir alan değişkeni kullanıyorum. Bunu özel bir pasif için tercih ediyorum, çünkü özel pasif, değişmezliği garanti etmiyor.

public class Abc
{ 
  private readonly int foo;

  public Abc(int fooToUse){
    foo = fooToUse;
  }

  public int Foo { get{ return foo; } }
}

2.) POCO değişkeni. Herhangi bir genel / özel kapsamda ayarlayabilen / ayarlayabilen basit bir değişken. Bu durumda sadece otomatik bir özellik kullanırdım.

public class Abc
{ 
  public int Foo {get; set;}
}

3.) ViewModel bağlama özellikleri. INotifyPropertyChanged'i destekleyen sınıflar için özel bir destek alanı değişkenine ihtiyacınız olduğunu düşünüyorum.

public class Abc : INotifyPropertyChanged
{
  private int foo;

  public int Foo
  {
    get { return foo; }
    set { foo = value;  OnPropertyChanged("foo"); }
  }
}

2
MVVM örneği için +1. Aslında soruyu ilk başlatan şey bu oldu.
Edward

4
+1: 2/3'ü AOP ile karıştırın ve INPC kullanmanın harika bir yolunu kullanın. [Bildirimler] public int Foo {olsun; Ayarlamak; }
Steven Evers

1
@Job Sınıfa erişen herhangi bir sınıfa, değişmezlik için özel bir belirleyici yeterlidir. Bununla birlikte, sınıf içinde, özel ayarlayıcı, ilk yapımın ardından, değerin tekrarlanan ayarlarını engellemez. 'Özel salt okunur küme' gibi bir dil özelliği kavramsal olarak bu problem etrafında çalışabilir, ancak mevcut değil.
Sheldon Warkentin

1
Ben C # için yeniyim, öyleyse söyle, neden kullanmak public int Foo {get; set;}yerine public int Foo?

1
Bir sınıf veya yapı POCO veya PODS gibi davranacaksa, özellikleri alanlara kaydırmanın asıl avantajı nedir? Özelliklerde sarma alanlarının, bir sınıf veya yapının değişmezleri içeriğine göre (belki de diğer nesnelerin eşleşmesi için güncellenmesini sağlayarak) gerek duyduğunda (belki de diğer nesnelerin eşleşmeleri için güncellenmesini sağlayarak) ihtiyaç duyduğunda veya gerektiğinde ihtiyaç duyduğunda yararlı olduğunu tamamen anlıyorum. Tüketicilerin kısıtlama veya yan etkiler olmadan herhangi bir sırayla herhangi bir değer yazabileceklerini, bir üye erişimciye hangi faydalı davranışların eklenebileceğini belirtir?
supercat

18

Genel olarak, yapıcıdaki alana atama yapar ve mülkü başka bir yerde kullanırım. Bu şekilde, biri mülke işlevsellik eklerse, hiçbir yerde kaçırmazsınız.

Kesinlikle bir performans faktörü değil. İyileştirici, sizin için basit bir sonuç getirecek veya ayarlayacaktır ve nihai MSIL kodu muhtemelen aynı olacaktır.


Alanın yapıcıda kullanılmasının özel bir nedeni var mı? Daha az garip yan etki olasılığı var mı?
Sign

4
@ İmzalı: Benim tahminim şu ki, mülkün üzerinde bir onaylama varsa (şimdi veya gelecekte), inşaat sırasında onaylama riskini almak istemezsiniz. Doğrulama bu aşamada mantıklı değildir, çünkü yapıcının işinin bitmesine kadar nesnenin kararlı olması garanti edilemez.
Steven Evers

@ İmzası: Hem de ne dediğine hem de Snorfus'un söylediğine. Veya bir mülkündeki değişiklikleri günlüğe kaydetmek istersem, büyük olasılıkla ilk ayarı kaydetmek istemiyorum. Ancak "genel olarak" dedim.
pdr

3
@Sign: problem şu: özelliğin set metodu bir alt sınıfta geçersiz kılınabiliyorsa, nesnenin veya tutarsız nesnenin yaratılması sırasında bir yan etkiye sahip olabilirsiniz (yani: geçersiz kılma özelliği herhangi bir değer ayarlamayacak şekilde programlanmıştır. o alan). Yapıcılarda özelliklerin kullanılması, yalnızca set yöntemi özelse veya sınıf mühürlendiğinde güvenlidir.
Diego,

4

Bağlı olmak.

İlk önce, mümkün olduğunda otomatik özellikleri tercih etmelisiniz:

public string MyValue {get;set;}

İkincisi, daha iyi bir yaklaşım muhtemelen özellikleri kullanmak olacaktır, eğer orada herhangi bir mantığınız varsa, muhtemelen kendiniz içinden geçiriyor olmalısınız, özellikle de bu mantık iş parçacığı senkronizasyonu ise.

Ancak, performansınızı engelleyebileceğini de dikkate almalısınız (biraz), yanlış senkronize ediyorsanız kendiniz kilitlenebilirsiniz ve bazen doğru yol da özellikteki mantığı dolaşmaktır.


3
Ben de severim public string MyValue {get; private set;}.
Meslek

3

Şey, düz noktaya yaklaşma yaklaşımı onu sadece değişkene atamak olacaktır, çünkü bir sınıfın içinde bir metodun içindesin ve sınıfın davranışını yine de kontrol ediyorsun.

Ancak özelliklerle ilgili bütün mesele, değişkeni soyutladıklarıdır. Örnekteki gibi basit bir mülk, basit bir ortak üye değişkeni üzerinde tamamen kullanılmazken, mülkler genellikle alıcıları ve belirleyicileri içinde ek şeyler yapar (veya yapmalıdır). Ve eğer sınıf içindeki özelliği değiştirirken bu şeylerin otomatik olarak yapılmasını istiyorsanız, özellik ayarı davranışı değiştiğinde her değişken atamasını değiştirmek zorunda kalmamak yerine değişken üzerinde özellik üzerinde çalışmak elbette daha temiz olacaktır.

Sadece kavramsal olarak bunun için bir nedene gerek var. Bu özellik aslında birden fazla üye değişkeni içerebilen nesnenin bazı iç durumuna erişmek için kullanılan bir tanıtıcıdır. Bu nedenle, kendinize, sadece altında yatan içsel durumu (veya yalnızca bir kısmını) veya bu durumu bir bütün olarak temsil eden soyut mülkü değiştirmek isteyip istemediğinizi sormanız gerekir ve çoğu zaman nesnenin daima olmasını istersiniz çünkü çoğu zaman tutarlı bir durum.


2

Bu mülk alma / ayarlama uygulamasının bazen sonradan değişmesi ihtimali varsa (örneğin, arama yaparken bir etkinlik oluşturmak istersiniz setveya getişlevinize daha sonra tembel bir değerlendirme mekanizması eklersiniz ), o zaman bu iyi bir fikir olabilir. büyük olasılıkla nadir - - açıkça vakalar sınıf içinde kodunuzu hariç hemen hemen her durumda özelliğini kullanacağı yok bu olay ya da tembel değerlendirme mekanizmalarını istiyorum kullanılacak.

Her neyse, ne yapacaksanız yapın, mülk uygulamasını daha sonra böyle bir şekilde değiştirdiğinizde, gerçekten mülküne erişilip erişilmeyeceğini kontrol etmek için sınıfınız içindeki tüm yerlere bakmanız gerekebilir. özel değişken kullanılacaktır.


2

Ben her zaman ortak mülkü kullanırım.

Genellikle, özellik ayarlandığında her zaman setbir özellik yöntemine eklendiğinde çalışması gereken bir mantık ve bunun yerine özel alanın ayarlanması, genel ayarlayıcı orada bulunan herhangi bir mantığı atlar.

Bu soruna yol açan MVVM hakkında bir yorumunuz var ve MVVM ile çalışırken bunun daha da önemli olduğunu düşünüyorum. Birçok nesne PropertyChangeayarlayıcıya bir bildirim gönderir ve diğer nesneler belirli özellikler değiştiğinde bazı eylemleri gerçekleştirmek için bu olaya abone olabilir. Özel değişkeni ayarlarsanız, PropertyChangedolayı elle de yükseltmediğiniz sürece bu işlemler asla yürütülmez .


+1 Evet, çoğu durumda (MVVM) PropertyChanged etkinliği bir zorunluluktur. Ve bu sadece mülkün içinde kovulabilir. İyi açıklama.
Edward

1

Genel olarak, bir mülkü ve geri alma alanını aldığınızda / ayarlarken yapmanız gerekenler size bağlıdır.

Çoğu zaman, sadece kodlar arasında tutarlı olmak için, halka açık erişimcileri uygun ve uygun olan her yerde kullanmalısınız. Bu, minimum kod değişikliğiyle refactor yapmanızı sağlar; Bu ayarı yapan yöntemin sınıftan çıkarılması ve destek alanının artık mevcut olmadığı (bir temel sınıf gibi) başka bir yere konması gerekiyorsa, kimin umurunda? İşi yapmak için sınıfın kendisinin olduğu her yerde kullanılabilir bir şey kullanıyorsunuz. Destek alanı, çoğu durumda, bir uygulama ayrıntısıdır; Sınıfınızın dışında kimse var olduğunu bilmemeli.

Destek alanını ne zaman kullanmanız gerektiğini ve mülk erişimcisi OLMADAN düşünebileceğiniz ana durum, erişimcinin çalıştırmak istemediğiniz ek bir mantık (doğrulama veya sınıftaki diğer durum bilgilerini güncelleme) olduğu durumudur. Bir nesnenin ilk popülasyonu bir örnektir; bir destek alanında da saklanan üçüncüyü hesaplamak için iki özellik değeri kullanan bir sınıfa sahip olabilirsiniz (kalıcılık nedenleriyle). Veritabanından veri verilen bu nesnenin yeni bir kopyasını başlatırken, her birinin üçüncü değeri yeniden hesapladığı özellik erişim sağlayıcıları, ihtiyaç duyulan diğer değer ayarlanmamışsa şikayet edebilir. Bu iki (veya üç) özelliğin başlangıç ​​değerlerini ayarlamak için destek alanlarını kullanarak, örnekleme mantığın normal şekilde çalışması için yeterince tutarlı bir duruma gelinceye kadar doğrulama / hesaplama mantığını atlarsınız.


0

Her zaman mantıklı olanı kullanın. Evet, cevap vermeme noktasına gelince çok sahte göründüğünü biliyorum.

Özelliklerin amacı, bir veri modeline güvenle erişebileceğiniz bir arabirim sağlamaktır. Çoğu durumda, aşağıdaki gibi veri arayüzüne her zaman güvenle erişmek istiyorsunuz:

public Foo Bar
{
  get { return _bar; }
  set { _bar = doSomethingTo(value); }
}

Ancak, diğer durumlarda, bir özelliği sadece bir veri modelinin görünümü olarak kullanıyor olabilirsiniz:

public Double SomeAngleDegrees
{
  get { return SomeAngleRadians * 180 / PI; }
  set { SomeAngleRadians = value * PI / 180; }
}

Radyan şeklini kullanmak mantıklıysa SomeAngle, o zaman elbette kullanın.

Sonunda, kendi kool yardımcınızı içtiğinizden emin olun. Halka açık API'niz dahili olarak çalışabilecek kadar esnek olmalıdır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.