özel ayarlayıcıları anlamak


94

C # 2 ile başlayan özel ayarlayıcılara sahip olmanın gerekliliğini anlamıyorum.

Benim için bir setter yöntemine sahip olmak, kullanıcının o sınıftaki bazı değişkenleri ayarlamasına izin veriyor. Bunu yaparken, değişkenleri doğrudan kullanıcılara açıklamayacağız. Bunun yerine, bunu bu public setter yöntemiyle yapmalarına izin verdik.

Bu benim için "kapsülleme" kullanıyor. Özel ayarlayıcıların kapsülleme uygulamanıza izin vereceğini iddia eden bazı argümanlar var.

Genel ayarlayıcı yöntemlerini kullanarak kapsüllemeyi kullanmıyor muyum? Neden özel pasörlere ihtiyacımız var?

Değişmez sınıf ile özel ayarlayıcıları olan bir sınıf arasındaki fark nedir?


1
Özel hazırlayıcıları çok sevdim - çirkin sınıfları yeniden düzenlememe yardımcı oldu. Onlar da imkansız ilan etmeye yapıp şöyle kerede sabit olmayan bir örnek değişkeni ayarlayın: private File settingsFile = null;kurucular ve sonra one: if (settingsFile == null) { settingsFile = GetSettingsFile() };. Kodu yeniden düzenlemek bazen beni ağlattı :). Yapıcıdan önce bir üye ayarlayabildiğiniz için, birden çok kurucu ile yapmanız gerektiği anlamına gelmez, bu mantığı takip etmeyi ZOR hale getirir. Özel ayarlayıcılar sizi yapıcı içinde veya daha sonra değerleri ayarlamaya zorlar.
Hamish Grubijan

Yanıtlar:


270

Mantıksal olarak.

Özel bir ayarlayıcının varlığı, auto özelliğini kullanabilmenizdir:

public int MyProperty { get; set; }

Sadece okunabilir hale getirmek istersen ne yapardın?

public int MyProperty { get; }

Kahretsin!! Ona kendi sınıfımdan erişemiyorum; Bunu normal bir mülk gibi yaratmalıyım:

private int myProperty;
public int MyProperty { get { return myProperty; } }

Hmm ... ama "Otomatik Mülk" özelliğini kaybettim ...

public int MyProperty { get; private set; }

AHHH .. bu daha iyi !!


1
Teşekkürler. Bu tekrar mantıklı
Dene

4
@ktutnik Bunu yaptığınız gibi ortaya koyduğunuz için teşekkür ederiz. Şimdi bana da mantıklı geliyor!
Vivek M. Chawla

4
Mükemmel şekilde resmedilmiş cevap.
imnk

3
Oh crap!! I can't access it from my own classC # 6.0'dan başlayarak bu yalnızca başlatma aşaması dışında doğrudur. Cevabımı görün stackoverflow.com/a/34223746/198797
tsemer

1
C # 6 ile # tsemer'in cevabına eklemek, ile {get; }eşdeğer DEĞİLDİR { get; private set; }. İlk yol için property.GetSetMethod(true)geri döner nullve ikincisi true. Bu beni şaşırttı.
emragins

38

Özel bir ayarlayıcı, salt okunur bir özelliğiniz varsa ve destek değişkenini açıkça bildirmek istemiyorsanız kullanışlıdır.

Yani:

public int MyProperty
{
    get; private set;
}

aynıdır:

private int myProperty;
public int MyProperty
{
    get { return myProperty; }
}

Otomatik olarak uygulanmayan özellikler için, mülkü içeriden ayarlamanın tutarlı bir yolunu sunar. sınıfınızın böylece doğrulama vb. Gerekiyorsa, yalnızca bir yere sahip olursunuz.

Son sorunuzu yanıtlamak için, MSDN'de özel ayarlayıcılar üzerinde şunları söyleyebilirsiniz:

Ancak, yalnızca bir dizi değeri (verileri) içine alan ve davranışları çok az olan veya hiç olmayan küçük sınıflar veya yapılar için, set erişimcisini özel olarak bildirerek nesnelerin değişmez hale getirilmesi önerilir.

Gönderen Oto Uygulanan özelliklerine MSDN sayfa


1
Üzgünüm, özel setçilerim olduğu için hala katma değeri göremiyorum. Pasörün açığa çıkmasını istemiyorsak, sadece alıcıya sahibiz. Doğrulayıcı eklemek istersek, genel bir ayarlayıcıya sahip olabilir ve ona doğrulama ekleyebiliriz. Erişilemeyen bir pasör neden gerekli? Anladığım kadarıyla "Bu arabayı al ama kullanamazsın" gibi, eğer yine de kullanmayacaksam neden arabayı bana vermek istiyorsun
Dene

@Dene - Yanlış olmadığı için kesinlikle bunu yapabilirsiniz. Otomatik uygulanan özelliklere sahip olmak zorunlu değildir.
ChrisF

Bunu ifade ettiğim şekilde yapmanın yanlış bir şey olmadığını biliyorum. Sadece C # 2 tarafından yapılan doğaçlamayı takdir etmek benim için. Etrafında çok fazla abartı var gibi görünüyor ama ne hissediyor ne de değerini göremiyorum.
Dene

@Dene, bu konudaki tüm aldatmacayı kaçırdım. Ancak sonunda bunu yapmanın mümkün olduğunu anladığımda mutluydum çünkü .Net 1.1 döneminden bazı uzun dersleri nasıl temizleyeceğimi biliyordum. Henüz ayarlanmamış özelliğin değerini muhtemelen kullanabilirsiniz, ancak bunu yapmak, null olarak ayarlanmış bir örnek üye değişkeninin değerini kullanmaktan daha az doğaldır.
Hamish Grubijan

Kodu basitleştirir. Tıpkı otomobil özellikleri gibi. C # için yapılan sonraki güncellemelerin çoğu, kodu daha kısa ve dolayısıyla okunabilir hale getirmekle ilgilidir. Yine de isterseniz işleri başka şekilde yapabilirsiniz - geriye dönük uyumluluk da büyük bir amaç gibi görünüyor. Sanırım bu bir zevk meselesi.
niico

18

Oldukça basit. Özel ayarlayıcılar, salt okunur genel veya korumalı mülkler oluşturmanıza izin verir.

Bu kadar. Tek sebep bu.

Evet, yalnızca alıcıyı belirterek salt okunur bir özellik oluşturabilirsiniz, ancak otomatik olarak yerleştirilen özelliklerde hem alma hem de ayarlama belirtmeniz gerekir, bu nedenle otomatik olarak uygulanan bir özelliğin salt okunur olmasını istiyorsanız , kullanmak özel ayarlayıcılar. Bunu yapmanın başka yolu yok.

Özel ayarlayıcıların, otomatik olarak uygulanan salt okunur özellikler için özel olarak yaratılmadığı doğrudur, ancak bunların kullanımı, diğer nedenlerden dolayı biraz daha ezoteriktir, büyük ölçüde salt okunur özellikler ve yansıtma ve serileştirmenin kullanımı etrafında merkezlenir.


2
Teşekkürler "otomatik uygulanan bir özelliğin salt okunur olmasını istiyorsanız, özel ayarlayıcılar kullanmanız gerekir". Bu bana mantıklı geliyor
Dene

18

C # 6.0 ve Otomatik Özellik Başlatıcıları için sözdizimi ile birlikte, satır içi veya yapıcı içinde yalnızca başlatma sırasında ayarlanan özellikler için özel ayarlayıcılara artık gerek yoktur.

Bu yeni sözdizimleri artık şunları derler:

Satır içi başlatılmış özellik

public class MyClass1 {
  public string MyProperty { get; } = "Aloha!"
}

Oluşturucu başlatılan özellik

public class MyClass2 {
  public string MyProperty { get; }

  public MyClass2(string myProperty) {
    MyProperty = myProperty;
  }
}

3
@Ziggler, gerçekten öyle değil. OP de sormuyor. Onlara sahip olmanın gerekliliğini anlamıyor. Bu yanıt: "Artık bu senaryoda bunlara sahip olmanız gerekmiyor".
tsemer

6

C # 2 ile başlayan özel ayarlayıcılara sahip olmanın gerekliliğini anlamıyorum.

Örneğin, fatura sınıfı, kullanıcının Öğeler özelliğine öğeleri eklemesine veya kaldırmasına izin verir, ancak kullanıcının Öğeler referansını değiştirmesine izin vermez (yani, kullanıcı Öğeler özelliğini başka bir öğe listesi nesne örneğine atayamaz).


public class Item
{
  public string item_code;
  public int qty;

  public Item(string i, int q)
  {
    this.item_code = i;
    this.qty = q;
  }
}

public class Invoice
{
  public List Items { get; private set; }

  public Invoice()
  {
    this.Items = new List();
  }
}

public class TestInvoice
{
  public void Test()
  {
    Invoice inv = new Invoice();
    inv.Items.Add(new Item("apple", 10));

    List my_items = new List();
    my_items.Add(new Item("apple", 10));

    inv.Items = my_items;   // compilation error here.
  }
}

Özel bir ayarlayıcıya sahip olmalarına rağmen özelliklerin genel alıcı aracılığıyla değiştirilebileceğini vurgulamak için +1.
user1725145

4

Örneğin, gerçek değişkeni özellik boyunca depolamadığınızı veya değeri bir şeyi hesaplamak için kullanmadığınızı varsayalım.

Böyle bir durumda, hesaplamanızı yapmak için bir yöntem oluşturabilirsiniz.

private void Calculate(int value)
{
 //...
}

Veya bunu kullanarak yapabilirsiniz

public int MyProperty {get; private set;}

Bu gibi durumlarda, her üye elementi bozulmamış özellikler refactor olarak sonrakini kullanmanızı tavsiye ederim.

Bunun dışında, mülkü bir Değişken ile eşlediğinizi söyleseniz bile. Böyle bir durumda, kodunuzun içine şöyle yazmak istersiniz:

public int myprop;
public int MyProperty {get { return myprop;}}

... ...

this.myprop = 30;

... ...
if(this.MyProperty > 5)
   this.myprop = 40;

Yukarıdaki kod korkunç görünüyor çünkü programcı Get için MyProperty ve Set için myprop kullanmak için her zaman dikkatli olmalı.

Tutarlılık için yeniden yapılandırıcıyı kodunuzda kullanırken Propoerty'yi yalnızca dışarıda okuyan bir Özel ayarlayıcı kullanabilirsiniz.


3

Sanırım birkaç kişi bunun etrafında dans etti, ancak benim için özel ayarlayıcıların değeri, bir mülkün davranışını bir sınıf içinde bile özetleyebilmenizdir. Abhishek'in belirttiği gibi, bir mülk her değiştiğinde bir mülk değişikliği olayını kovmak istiyorsanız, ancak bir mülkün halka okunmasını / yazılmasını istemiyorsanız, o zaman ya özel bir ayarlayıcı kullanmalısınız ya da destek alanını değiştirdiğiniz herhangi bir olay. İkincisi hataya meyillidir çünkü unutabilirsiniz. Buna bağlı olarak, bir özellik değerinin güncellenmesi, bir hesaplamanın gerçekleştirilmesine veya başka bir alanın değiştirilmesine veya bir şeyin tembel bir şekilde başlatılmasına neden oluyorsa, bunu yaptığınız her yerde yapmayı hatırlamak yerine, bunu özel ayarlayıcıya da sarmak isteyeceksiniz. destek alanının kullanımı.


2

Kapsülleme, bir nesnenin durumunun yalnızca tanımlanmış bir arabirim aracılığıyla gerçekleştiği anlamına gelir ve bu nedenle sınıf, bu durumun her zaman geçerli olduğundan ve sınıfın amacına uygun olduğundan emin olabilir.

Bu nedenle bazı durumlarda, bir alanı herkese açık olarak göstermek, kapsülleme ilkesine mükemmel bir şekilde uymaktadır - alan için tüm olası değerler, diğer tüm alanların diğer tüm olası değerleri ile geçerlidir ve bu nedenle programcı, alana etkin bir şekilde izin vermeye karar verebilir. dış kod tarafından serbestçe manipüle edilebilir.

Bu durumlar, çoğunlukla "düz eski veriler" olan sınıflarla sınırlıdır. Onlar da bu konuda çok ilginç değiller, bu kadar onlar için yeterli.

Diğer durumlarda, diğer dillerde, bir alıcı ve ayarlayıcı yöntemine sahip int getId()olunur , bir değer elde etmek ve void setId(int val)onu güncellemek gibi bir şey.

Özellikler, bir alanı okumak ve yazmak için kullanacağımız gibi, bu tür yöntemlerle okumak ve yazmak için aynı sözdizimini kullanmamıza izin verir. Bu hayati olmasa da iyi bir sözdizimsel şekerdir.

(Aslında, yansımanın çalışma şekli nedeniyle ve DataBinder.Evalbir alan iyi çalışsa bile bir mülke sahip olmak kullanışlı olabilir, ancak bu başka bir mesele).

Özel ayarlayıcılar tanıtılıncaya kadar (aslında, aynı blokta özel bir ayarlayıcı ve genel veya korumalı bir alıcıya sahip olmak için C # 2 ile değişen sözdizimi), özel ayarlayıcının işini yapmak için özel bir yönteme sahip olabilirdik, yani özel ayarlayıcılar gerçekten gerekli değildir. Yine de kullanışlıdırlar, bu yüzden sözdizimsel şeker olsa da oldukça kullanışlıdırlar.

Kapsülleme, ayarlayıcılarınızın (veya alıcılarınızın) kamuya açık, özel, korumalı veya dahili olup olmadıklarının değil, uygun olup olmadıklarının bir meselesidir . Her alanın özel (ve bu konuda readonly) varsayılan olarak başlayın ve ardından gerektiğinde bu alanları değiştiren üyeler (özellikler veya yöntemler olsun ) ekleyin ve değiştikçe nesnenin geçerli kalmasını sağlayın . Bu, bir sınıfın değişmezinin korunmasını sağlar , yani içinde bulunabileceği geçerli durum kümesini tanımlayan kuralların asla bozulmaması gerekir (kurucular ayrıca, sınıfın böyle geçerli bir durumda başladığından emin olarak yardımcı olurlar).

Son sorunuza gelince, değişmez olmak, bir sınıfın genel, korumalı veya dahili belirleyicileri olmadığı ve herhangi bir alanı değiştiren genel, korumalı veya dahili yöntemleri olmadığı anlamına gelir . Bunun dereceleri vardır, C # 'da olası üç derece vardır:

  1. Bir sınıfın tüm örnek alanlarıdır readonly, bu nedenle özel kod bile onu değiştiremez. Değişmez olduğu garanti edilir (değiştirmeye çalışan herhangi bir şey derlenmez) ve muhtemelen bunun arkasında optimizasyonlar yapılabilir.

  2. Bir sınıf dışarıdan değişmez çünkü hiçbir kamu üyesi hiçbir şeyi değiştirmez, ancak kullanımıyla readonlyiçeriden değiştirilmeyeceği garanti edilmez.

  3. Bir sınıf dışarıdan görüldüğü gibi değişmezdir, ancak bazı durumlar bir uygulama ayrıntısı olarak değişir. Örneğin, bir alan hafızaya alınabilir ve bu nedenle dışarıdan onu elde etme girişimi aynı değeri alırken, bu tür ilk girişim onu ​​gerçekten hesaplar ve ardından sonraki denemelerde geri almak için depolar.


1

Aşağıdaki senaryoyu desteklemek istiyorsanız, özel bir ayarlayıcıya ihtiyacınız var (sadece bunun için değil, aynı zamanda iyi bir nedeni göstermelidir): Sınıfınızda salt okunur olan bir Özelliğe sahipsiniz, yani sadece sınıfın kendisinin değişmesine izin verilir , ancak örneği oluşturduktan sonra onu değiştirebilir. Bağlamalar için daha sonra bir PropertyChanged olayını tetiklemeniz gerekir, tercihen bu (özel) özellik ayarlayıcıda yapılmalıdır. Aslında, PropertyChanged olayını sınıfın başka bir yerinden tetikleyebilirsiniz, ancak bunun için özel ayarlayıcıyı kullanmak "iyi vatandaşlıktır", çünkü mülkiyet değişikliği tetikleyicilerinizi sınıfınızın her yerine dağıtmazsınız, ancak bunu aynı yerde tutarsınız. mülk, ait olduğu yer.


1

Evet, özellikleri kullanarak kapsüllemeyi kullanıyorsunuz, ancak kapsüllemede, özelliklerin nasıl okunup yazılacağını kontrol etmekten daha fazla nüans vardır. Sınıfın dışından ayarlanacak bir özelliğin reddedilmesi, hem sağlamlık hem de performans açısından yararlı olabilir.

Değişmez bir sınıf, oluşturulduktan sonra değişmeyen bir sınıftır, bu nedenle özellikleri korumak için özel ayarlayıcılara (veya hiç ayarlayıcıya gerek yoktur) ihtiyaç vardır.

Özel ayarlayıcılar, C # 3'te tanıtılan özellik kısaltmasıyla daha sık kullanılmaya başlandı. C # 2'de ayarlayıcı genellikle ihmal edildi ve özel verilere ayarlandığında doğrudan erişildi.

Bu mülk:

public int Size { get; private set; }

aynıdır:

private int _size;
public int Size {
  get { return _size; }
  private set { _size = value; }
}

dışında, destek değişkeninin adı derleyici tarafından dahili olarak oluşturulur, bu nedenle ona doğrudan erişemezsiniz.

Steno özelliği ile, arka değişkene doğrudan erişemeyeceğiniz için, salt okunur bir özellik oluşturmak için özel ayarlayıcıya ihtiyaç vardır.


Doğru hatırlıyorsam, C # 2.0'da getve setöncesinde farklı erişim değiştiricileriniz olamazdı . Ayrıca, bahsettiğiniz otomatik olarak uygulanan kısaltma 3.0 olduğu için 2.0 ve 3.0'ı karıştırdığınızı düşünüyorum.
Anthony Pegram

1

C # 2 ile başlayan özel ayarlayıcılara sahip olmanın gerekliliğini anlamıyorum.

Örnek kullanım:

'UserInfo'Bir özellik içeren bir uygulama nesnesi örneğim varSessionTokenIDV1Sınıfımın tüketicilerine ifşa etmek istemediğim sahibim.

Ayrıca bu değeri sınıfımdan belirleme yeteneğine de ihtiyacım var.

Çözümüm, özelliği gösterildiği gibi kapsüllemek ve ayarlayıcıyı özel yapmaktı, böylece oturum belirtecinin değerini, örnekleme kodunun da ayarlamasına izin vermeden (veya hatta benim durumumda görmeden) ayarlayabilirim.

public class UserInfo
{
   public String SessionTokenIDV1 { get; set; }

}


public class Example
{
  // Private vars
  private UserInfo _userInfo = new UserInfo();

  public string SessionValidV1
  {
    get { return ((_userInfo.SessionTokenIDV1 != null) && (_userInfo.SessionTokenIDV1.Length > 0)) ? "set" : "unset"; }
    private set { _userInfo.SessionTokenIDV1 = value; }
  }
}

Düzenleme: Sabit Kod Etiketi Düzenleme: Örnekte düzeltilmiş hatalar var


-1

Krediler https://www.dotnetperls.com/property .

özel ayarlayıcılar salt okunur alanlarla aynıdır. Yalnızca yapıcıda ayarlanabilirler. Dışarıdan ayarlamaya çalışırsanız, derleme zamanı hatası alırsınız.

public class MyClass
{
    public MyClass()
    {
        // Set the private property.
        this.Name = "Sample Name from Inside";
    }
     public MyClass(string name)
    {
        // Set the private property.
        this.Name = name;
    }
    string _name;
    public string Name
    {
        get
        {
            return this._name;
        }
        private set
        {
            // Can only be called in this class.
            this._name = value;
        }
    }
}

class Program
{
    static void Main()
    {
        MyClass mc = new MyClass();
        Console.WriteLine(mc.name);

        MyClass mc2 = new MyClass("Sample Name from Outside");
        Console.WriteLine(mc2.name);
    }
}

Lütfen sınıfın dışından ayarlamaya çalıştığımda aşağıdaki ekran görüntüsüne bakın.

görüntü açıklamasını buraya girin

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.