C # 'da özel özellikleri kullanmak için herhangi bir neden var mı?


246

Sadece C # özellik yapısının özel erişim değiştirici ile de kullanılabileceğini fark ettim :

private string Password { get; set; }

Bu teknik olarak ilginç olsa da, özel bir alan daha az tören içerdiğinden bunu ne zaman kullanacağımı hayal edemiyorum :

private string _password;

ve ben şimdiye kadar içten edebilmek bırakmamızı gerektiren hayal bile edemiyorum olsun ama set veya set ama olsun özel alan:

private string Password { get; }

veya

private string Password { set; }

ancak iç içe / devralınan sınıfları olan bir kullanım durumu vardır veya bir get / set özelliğinin değerini geri vermek yerine sadece mantık içerebilirse de, özellikleri kesinlikle basit tutmaya ve açık yöntemlerin herhangi bir mantık yapmasına izin verirsem, örn GetEncodedPassword().

Herhangi bir nedenle C # özel özellikleri kullanan veya teknik olarak mümkün-ama nadiren kullanılan-gerçek kod yapıları sadece biri mi?

ek

Güzel cevaplar, bunları okurken özel mülkler için bu kullanımları kaldırdım:

  • özel alanların tembel olarak yüklenmesi gerektiğinde
  • özel alanlar fazladan mantığa ihtiyaç duyduğunda veya hesaplanan değerler olduğunda
  • çünkü özel alanların hata ayıklaması zor olabilir
  • "kendinize bir sözleşme sunmak" için
  • serileştirmenin bir parçası olarak açık bir özelliği dahili olarak dönüştürmek / basitleştirmek
  • sınıfınızda kullanılacak global değişkenleri kaydırma

Özel mülkler tarafından teşvik edilen teknik kendi kendine kapsülleme - bakınız: sourcemaking.com/refactoring/self-encapsulate-field
LBushkin

Yanıtlar:


212

Bir değeri önbelleğe almam gerekiyorsa ve tembel yüklemek istiyorsanız bunları kullanıyorum.

private string _password;
private string Password
{
    get
    {
        if (_password == null)
        {
            _password = CallExpensiveOperation();
        }

        return _password;
    }
}

42
bunun için güzel bir ortak desenreturn _password ?? (_password = CallExpensiveOperation());
Marc

1
@EvAlex Lazy <T> kullanabiliyorsanız tercih edilebilir. Ancak yalnızca statik şeyler kullanabilir, böylece (statik olmayan) yöntemlere veya diğer üyelere erişemezsiniz. Bu arada return _password ?? (_password = CallExpensiveOperation());bir süredir tek satır sözdizimini tercih ediyorum . Ya da aslında Resharper bunu tercih ediyor :).
Bart

4
@Marc, C # 6'dan bu yana bir getiri ve dönüş yazmanıza bile gerek yok. private string Password => _password ?? (_password = CallExpensiveOperation());
Otto Abnormalverbraucher

1
C # 8 ile daha da kısa:private string Password => _password ??= CallExpensiveOperation();
Dave M

2
@Bas Tembel yükleme değil çünkü içerilen CallExpensiveOperation();nesnenin yapımı / başlatılması sırasında ve özelliğe ilk erişildiğinde değil çağrılır.
Stefan Podskubka

142

Kodumda bunun birincil kullanımı, diğerlerinin de belirttiği gibi, tembel başlatmadır.

Özel mülklerin alanlar üzerindeki diğer bir nedeni, özel mülklerin hata ayıklaması, özel alanlardan çok daha kolay olmasıdır. Sık sık "bu alan beklenmedik bir şekilde ayarlanıyor; bu alanı ayarlayan ilk arayan kim?" ve ayarlayıcıya bir kırılma noktası koyabilir ve git tuşuna basmanız çok daha kolaydır. Oraya giriş yapabilirsiniz. Performans metriklerini oraya koyabilirsiniz. Hata ayıklama derlemesinde çalışan tutarlılık denetimleri koyabilirsiniz.

Temel olarak, aşağıya gelir: kod verilerden çok daha güçlüdür . İhtiyacım olan kodu yazmama izin veren herhangi bir teknik iyi bir teknik. Alanlar onlara kod yazmanıza izin vermez, özellikler yazıyor.


5
"Kod veriden çok daha güçlü" diyor musunuz? Google'da sizi işaret eden referanslar döndürülür. Sadece bilmek istiyorum, böylece gerektiğinde doğru teklif verebilirim.
Joan Venge

24
@Joan: Bilmiyorum. Ya uydurdum ya da başka birinin söylediklerini duydum ve "vay be, bunu tamamen çalmalıyım ve sonra kimden çaldığımı unutmalıyım" diye düşündüm.
Eric Lippert

1
+ CodeLens size mülkün referans verildiğini söyler
UuDdLrLrSs

43

iç içe / devralınan sınıflara sahip bir kullanım durumu olabilir veya bir get / set'in yalnızca mülkün değerini geri vermek yerine mantık içerebileceği bir durum vardır

Ben bir mülk alıcı veya setter mantık gerek yokken ben şahsen bunu kullanın. Özel bir özelliği bile, bir özelliği kullanmak, kodunuzu geleceğe hazırlamaya yardımcı olur, böylece gerekirse mantığı bir alıcıya daha sonra ekleyebilirsiniz.

Bir özellik sonunda ekstra mantık gerektirebilir, bazen bir alan kullanmak yerine özel bir özelliğe sarın, sadece kodumu daha sonra değiştirmek zorunda değilsiniz.


Yarı ilişkili bir durumda (sorunuzdan farklı olsa da), genel mülklerde özel ayarlayıcıları sık sık kullanıyorum:

public string Password 
{
    get; 
    private set;
}

Bu size halka açık bir alıcı verir, ancak ayarlayıcıyı gizli tutar.


+1 mantıklı: "Bir özelliğin sonunda fazladan mantık gerektirebileceğini düşünürsem, bazen daha sonra kodumu değiştirmek zorunda kalmam için bir alan kullanmak yerine özel bir mülke sararım."
Edward Tanguay

7
özel
seterler

20

Yalnızca özel mülkler için iyi bir kullanım hesaplanan değerlerdir. Birkaç kez özel salt okunur ve sadece türümdeki diğer alanlar üzerinde bir hesaplama yapmak özellikleri vardı. Bir yönteme layık değildir ve diğer sınıflar için ilginç değildir, bu yüzden özel mülkiyettir.


20

Tembel başlatma, temiz olabilecekleri bir yerdir, örn.

private Lazy<MyType> mytype = new Lazy<MyType>(/* expensive factory function */);

private MyType MyType { get { return this.mytype.Value; } }

// In C#6, you replace the last line with: private MyType MyType => myType.Value;

Sonra yazabilirsiniz: Tembel bir şekilde tembel bir şekilde tek bir yerde başlatıldığı gerçeğini this.MyTypedeğil, her this.mytype.Valueyere yazın.

Utanç verici olan bir şey, C # 'ın, tamamen gizlemek ve yalnızca mülk yoluyla erişilebilmesini sağlamak için mülkün destek alanını kapsamayı (yani, özellik tanımında bildirmek) desteklememesidir.


2
Burada kapsam belirleme yönü olması gerektiği konusunda hemfikirdi.
Chris Marisic

5
Aynı tekniği sık sık kullanıyorum ve bir alanın kod gövdesine dahil edilmesini de diledim. Güzel bir özellik ama düşük öncelikli.
Eric Lippert

5
İçinde yer alan @Eric Lippert - field-declarationler accessor-declarationsuzun zamandır C # istek listemde 1 numaraya yerleşti. Eğer bunu bazı (gerçek) gelecekteki versiyonda tasarlayıp uygulayabilirseniz, o zaman size bir kek pişireceğim.
Jeffrey L Whitledge

13

Aklıma gelen tek kullanım

private bool IsPasswordSet 
{ 
     get
     {
       return !String.IsNullOrEmpty(_password);
     }
}

Diğer özel değişkenlerden hesaplanan faydalı özellik sınıfı için +1
Daren Thomas

2
Neden özel bir yöntem kullanmıyorsunuzprivate bool IsPasswordSet() { return !String.IsNullOrEmpty(_password); }
Roman

10

Özellikler ve alanlar bire bir değildir. Bir özellik, bir sınıfın arabirimi hakkındadır (ister kamusal ister iç arabirimi hakkında konuşuyor olsun), bir alan sınıfın uygulamasıyla ilgilidir. Özellikler sadece alanları ortaya çıkarmanın bir yolu olarak görülmemeli, sınıfın amacını ve amacını ortaya çıkarmanın bir yolu olarak görülmelidir.

Tıpkı mülklerinizi, tüketicilerinize sınıfınızı neyin oluşturduğuna dair bir sözleşme sunmak için kullandığınız gibi, benzer nedenlerden dolayı kendinize de bir sözleşme sunabilirsiniz. Evet, mantıklı olduğunda özel mülkler kullanıyorum. Bazen özel bir mülk, tembel yükleme, bir mülkün gerçekten birkaç alan ve yönün bir araya gelmesi olduğu veya bir mülkün her çağrıda sanal olarak somutlaştırılması gerektiği gibi uygulama ayrıntılarını gizleyebilir DateTime.Now. Sınıfın arka tarafında bunu kendiniz için bile zorlamanın mantıklı olduğu zamanlar kesinlikle vardır.


+1: "Çok benzer nedenlerden dolayı kendinize bir sözleşme de sunabilirsiniz" mantıklı
Edward Tanguay

8

Onları serileştirmede, DataContractSerializerbu kullanımı destekleyen veya desteklemeyen protobuf -net gibi şeylerle kullanıyorum XmlSerializer. Serileştirmenin bir parçası olarak bir nesneyi basitleştirmeniz gerekiyorsa yararlıdır:

public SomeComplexType SomeProp { get;set;}
[DataMember(Order=1)]
private int SomePropProxy {
    get { return SomeProp.ToInt32(); }
    set { SomeProp = SomeComplexType.FromInt32(value); }
}

6

Her zaman yaptığım bir şey, "global" değişkenleri / önbelleği HttpContext.Current

private static string SomeValue{
  get{
    if(HttpContext.Current.Items["MyClass:SomeValue"]==null){
      HttpContext.Current.Items["MyClass:SomeValue"]="";
    }
    return HttpContext.Current.Items["MyClass:SomeValue"];
  }
  set{
    HttpContext.Current.Items["MyClass:SomeValue"]=value;
  }
}

5

Bunları arada bir kullanıyorum. Mülkte kolayca bir kesme noktası koyabildiğinizde veya bir günlük ifadesi vb. Ekleyebildiğinizde, hata ayıklamayı kolaylaştırırlar.

Daha sonra verilerinizin türünü bir şekilde değiştirmeniz veya yansıma kullanmanız gerekiyorsa da yararlı olabilir.


aynen; bir get / set içinde mantık varsa, bazen özel veya korumalı bir özellik kullanabilirim. Genellikle ne kadar mantığa bağlıdır: mülkte yapacağım basit mantık, genellikle yardımcı fonksiyon kullanacağım bir sürü mantık. Kodu en sürdürülebilir hale getiren ne olursa olsun.
TechNeilogy

5

Ben sık kullanılan alt özelliklerine erişmek için kodu azaltmak için özel özellikleri kullanın.

    private double MonitorResolution
    {
        get { return this.Computer.Accesories.Monitor.Settings.Resolution; }
    }

Birçok alt özellik varsa yararlıdır.


2

Üyeleri yalnızca alma / ayarlama yöntemleriyle, hatta özel yöntemlerle değiştirmek yaygın bir uygulamadır. Şimdi, bunun arkasındaki mantık, get / setinizin her zaman belirli bir şekilde davrandığını (örneğin, olayları tetiklemek gibi) biliyorsunuz, çünkü bunlar özellik şemasına dahil edilmeyecektir ... ama eski alışkanlıklar zor ölüyor.


2

Özellik kümesi veya get (tembel başlatmayı düşün) ile ilişkili mantık olduğunda ve özellik sınıfın birkaç yerinde kullanıldığında mükemmel bir anlam ifade eder.

Sadece düz bir destek alanı ise? Akla hiçbir şey iyi bir sebep olarak gelmez.


2

Bu sorunun çok eski olduğunu biliyorum ama aşağıdaki bilgiler mevcut cevapların hiçbirinde yoktu.

Ne zaman dahili olarak alabileceğimi ancak ayarlayamayacağımı hayal edemiyorum

Bağımlılıklarınızı enjekte ediyorsanız, salt okunur bir Özelliği göstereceği için bir ayarlayıcıya değil bir Mülk üzerinde Alıcıya sahip olmak isteyebilirsiniz. Başka bir deyişle, Özellik yalnızca yapıcıda ayarlanabilir ve sınıf içindeki başka bir kodla değiştirilemez.

Ayrıca Visual Studio Professional, alanınızın ne kullanıldığını görmenizi kolaylaştıran bir alan değil, bir Özellik hakkında bilgi verecektir.

PorpField


1

Kimsenin belirtmediği gibi, verileri doğrulamak veya değişkenleri kilitlemek için kullanabilirsiniz.

  • onaylama

    string _password;
    string Password
    {
        get { return _password; }
        set
        {
            // Validation logic.
            if (value.Length < 8)
            {
                throw new Exception("Password too short!");
            }
    
            _password = value;
        }
    }
  • Kilitleme

    object _lock = new object();
    object _lockedReference;
    object LockedReference
    { 
        get
        {
            lock (_lock)
            {
                return _lockedReference;
            }
        }
        set
        {
            lock (_lock)
            {
                _lockedReference = value;
            }
        }
    }

    Not: Bir referansı kilitlerken, referans alınan nesnenin üyelerine erişimi kilitlemezsiniz.

Tembel referans: Tembel yükleme yaparken, günümüzde AsyncLazy olan async'i yapmanız gerekebilir . Visual Studio SDK 2015 sürümünden daha eski sürümler kullanıyorsanız veya kullanmıyorsanız, AsyncEx'in AsyncLazy yazılımını da kullanabilirsiniz .


0

Müstehcen alanların daha egzotik kullanımlarından bazıları şunlardır:

  • kullanmanız refya outda değer kullanmanız gerekir - belki bir Interlockedsayaç olduğu için
  • o olduğu amaçlanan bir örneğin temel düzenini temsil etmek structaçık düzen ile (belki ++ bir C eşlemek dökümü, ya daunsafe kod)
  • Tarihsel olarak bu tür BinaryFormatterotomatik alan işleme ile birlikte kullanılmıştır (otomatik desteklere geçmek adları değiştirir ve böylece serileştiriciyi bozar)
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.