C # 3.0+ Özellik ve Alan Arasındaki Fark


140

Ben bir alan ve C # bir özellik arasındaki fark nedir bir kopyası gibi görüyorum ? ama sorumun küçük bir farkı var (benim açımdan):

Bunu bildiğimde

  • Sınıfımı "sadece özellikler üzerinde çalışan teknikler" ile kullanmayacağım ve
  • Alıcı / ayarlayıcıda doğrulama kodu kullanmayacağım.

Mülkün ayarlanmasında bir tür kontrol gibi herhangi bir fark var mı (stil / gelecekteki geliştirme olanlar hariç)?

Arasında herhangi bir ek fark var mı:

public string MyString { get; set; }

ve

public string myString;

(İlk sürümün C # 3.0 veya üstü gerektirdiğini ve derleyicinin özel alanları oluşturduğunu biliyorum.)


Yanıtlar:


117

Kapsülleme.

İkinci durumda az önce bir değişken tanımladınız, birincisinde, değişkenin etrafında bir alıcı / ayarlayıcı var. Bu nedenle, değişkeni daha sonraki bir tarihte doğrulamak istediğinize karar verirseniz - çok daha kolay olacaktır.

Ayrıca Intellisense'de farklı görünüyorlar :)

Düzenleme: OPs güncelleme sorusu için güncelleme - burada diğer önerileri göz ardı etmek istiyorsanız, diğer nedeni sadece iyi bir OO tasarımı olmamasıdır. Ve bunu yapmak için çok iyi bir nedeniniz yoksa, her zaman ortak bir değişken / alan üzerinde bir mülk seçin.


9
Neden daha kolay olacak? Bir alanı mülke dönüştürmemi ve özel bir destek alanı eklememi ne engeller? Bu arama kodunu nasıl etkiler?
Serge Wautier

30
@Serge - Zaten derlenmiş kodu etkiler. Örneğin, birkaç uygulama tarafından kullanılan bir kitaplık geliştiriyorsanız, bir alanı bu kitaplıktaki bir özelliğe değiştirmek her uygulamanın yeniden derlenmesini gerektirir. Bir mülk olsaydı, endişelenmeden mülkü güncelleyebilirsiniz.
Dustin Campbell

Sana tamamen katılıyorum, daima özellikleri kullanıyorum. Sadece olası bir farkı merak ediyordum
p4bl0

24
Kod tüketen her zaman etkilenen sınıfla aynı zamanda yeniden derlenirse (böylece iç ve
dışta

1
vay Shuggy yorumunuzu tam olarak aradığım cevap!
p4bl0

160

Alanlar ve özellikler aynı görünür, ancak değildir. Özellikler yöntemlerdir ve bu nedenle özellikler için desteklenmeyen bazı şeyler vardır ve özelliklerle birlikte olabilecek, ancak alanlar söz konusu olmadığında bazı şeyler olabilir.

İşte farklılıkların listesi:

  • Alanlar, out/refbağımsız değişkenlere giriş olarak kullanılabilir . Özellikler olamaz.
  • Bir alan, birden çok kez çağrıldığında her zaman aynı sonucu verir (birden fazla iş parçacığı ile ilgili sorunları bırakırsak). Gibi bir özellik DateTime.Nowher zaman kendisine eşit değildir.
  • Özellikler istisnalar atabilir - alanlar bunu asla yapmaz.
  • Özelliklerin yan etkileri olabilir veya yürütülmesi çok uzun sürebilir. Alanların hiçbir yan etkisi yoktur ve her zaman belirtilen tür için beklenildiği kadar hızlı olacaktır.
  • Özellikler alıcılar / ayarlayıcılar için farklı erişilebilirliği destekler - alanlar desteklemez (ancak alanlar yapılabilir readonly)
  • Yansıma kullanılırken, özellikler ve alanlar farklı olarak ele alınır, MemberTypesböylece farklı konumlandırılırlar ( örneğin, GetFieldsvs GetProperties)
  • JIT Derleyici, saha erişimine kıyasla mülk erişimini çok farklı şekilde ele alabilir. Ancak aynı yerel koda derlenebilir ancak farkın kapsamı oradadır.

11
Ancak, iyi uygulamaların kullanılması durumunda bu noktaların bir kaçının farklılık olmaması gerektiğini unutmayın . Yani, mülklerin gerçekten hiçbir zaman yan etkileri olmamalı ve yürütülmesi uzun sürmemelidir.
Noldorin

15
@Noldorin: Kabul ediyorum, ancak maalesef buradaki anahtar kelime olmalı . Alanlarda bu davranış garanti edilir. Alanları kullanmanız gerektiğini söylemiyorum, ama anlamsal farklılıkların farkında olmak önemlidir.
Brian Rasmussen

4
Evet, yeterince adil. Acemi programcıların ne yazık ki bu şeyler hakkında bir ipucu yok ...
Noldorin

2
Ayrıca, özelliklerin bir kurucuda başlatılması gerekirken, alanların alan başlatıcısı olabilir.
Dio F

3
Bu cevabın kabul edilen cevaptan daha büyük olduğunu düşünüyorum. Ben her zaman alanlar üzerinde özellikleri tercih "kabul edilebilir" yolu kötü düşünme olduğunu düşünmeye başladım. Yalnızca verilerle ilgilenmeniz gerekiyorsa bir alan kullanın. Verilere işlevsellik uygulamanız gerekiyorsa, bir yöntem kullanın. Mülklerin farkında olmadığınız yan etkileri olabileceğinden (özellikle kütüphaneyi tasarlamadıysanız ve çok az dokümantasyona sahipseniz), çoğu durumda bana karşı sezgisel görünüyorlar.
David Peterson

41

Birkaç hızlı, belirgin fark

  1. Bir mülkte erişimci anahtar kelimeleri bulunabilir.

    public string MyString { get; private set; }
  2. Bir mülk, inişlerde geçersiz kılınabilir.

    public virtual string MyString { get; protected set; }

1
mmh .. nr 2 ilginç .. bunu düşünmedim
p4bl0 9

14

Temel fark, bir alanın bellekteki belirtilen türdeki verilerin saklandığı bir konum olmasıdır. Özellik, belirtilen türde bir değeri almak veya ayarlamak için yürütülen bir veya iki kod birimini temsil eder. Bu erişimci yöntemlerinin kullanımı, alan gibi davranan bir üye kullanılarak sözdizimsel olarak gizlenir (atama işleminin her iki tarafında da görünebilir).


11

Erişimciler alanlardan daha fazlasıdır. Diğerleri zaten birkaç önemli farklılığa dikkat çekti ve ben bir tane daha ekleyeceğim.

Özellikler arabirim sınıflarında yer alır. Örneğin:

interface IPerson
{
    string FirstName { get; set; }
    string LastName { get; set; }
}

Bu arayüz çeşitli şekillerde tatmin edilebilir. Örneğin:

class Person: IPerson
{
    private string _name;
    public string FirstName
    {
        get
        {
            return _name ?? string.Empty;
        }
        set
        {
            if (value == null)
                throw new System.ArgumentNullException("value");
            _name = value;
        }
    }
    ...
}

Bu uygulamada, Personsınıfın geçersiz duruma geçmesini ve arayanın atanmamış mülkten boş kalmasını önlüyoruz.

Ancak tasarımı daha da ileriye taşıyabiliriz. Örneğin, arabirim ayarlayıcıyla ilgilenmeyebilir. IPersonArayüz tüketicilerinin , mülkün ayarlanmasıyla değil, sadece mülkle ilgilendiklerini söylemek oldukça meşrudur :

interface IPerson
{
    string FirstName { get; }
    string LastName { get; }
}

PersonSınıfın önceki uygulaması bu arabirimi karşılar. Arayanın özellikleri ayarlamasına izin vermesi, (tüketen IPerson) tüketicilerin bakış açısından anlamsızdır . Somut uygulamanın ek işlevselliği, örneğin inşaatçı tarafından dikkate alınır:

class PersonBuilder: IPersonBuilder
{
    IPerson BuildPerson(IContext context)
    {

        Person person = new Person();

        person.FirstName = context.GetFirstName();
        person.LastName = context.GetLastName();

        return person;

    }
}

...

void Consumer(IPersonBuilder builder, IContext context)
{
    IPerson person = builder.BuildPerson(context);
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}

Bu kodda, tüketici mülkiyet belirleyicileri bilmiyor - bunu bilmek onun işi değil. Tüketicinin sadece alıcılara ihtiyacı vardır ve alıcıları arayüzden, yani sözleşmeden alır.

Tamamen geçerli bir başka uygulaması, IPersondeğişmez bir kişi sınıfı ve ilgili bir kişi fabrikası olacaktır:

class Person: IPerson
{
    public Person(string firstName, string lastName)
    {

        if (string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName))
            throw new System.ArgumentException();

        this.FirstName = firstName;
        this.LastName = lastName;

    }

    public string FirstName { get; private set; }

    public string LastName { get; private set; }

}

...

class PersonFactory: IPersonFactory
{
    public IPerson CreatePerson(string firstName, string lastName)
    {
        return new Person(firstName, lastName);
    }
}
...
void Consumer(IPersonFactory factory)
{
    IPerson person = factory.CreatePerson("John", "Doe");
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}

Bu kodda örnek tüketici bir kez daha özellikleri doldurma bilgisine sahip değildir. Tüketici sadece alıcılar ve somut uygulamalarla ilgilenir (ve arkasındaki iş mantığı, adın boş olup olmadığını test etmek gibi) uzman sınıflara bırakılır - inşaatçılar ve fabrikalar. Tüm bu işlemler tarlalarla tamamen imkansızdır.


7

İlki:

public string MyString {get; set; }

bir mülktür; ikincisi ( public string MyString) bir alanı belirtir.

Aradaki fark, bazı tekniklerin (örnekler için ASP.NET veri tabanı oluşturma), yalnızca özellikler üzerinde çalıştığı, alanlar üzerinde çalışmadığıdır. Aynı şey XML Serileştirmesi için de geçerlidir: yalnızca özellikler serileştirilir, alanlar serileştirilmez.


8
Yanlış. XML Serileştirmesi ortak alanları serileştirir.
Serge Wautier

2
Olabilir. Ancak bir sınıftan bir Nesne Veri Kaynağı oluşturduğunuzda, alanları değil yalnızca özellikleri kullanabilirsiniz. (Yanlış bir şey yapmadıkça: P)
Svish

DRY için iyi;) ama bir kez daha yazıyorum, C # dilinde özelliğin güçlü rolünü seviyorum. Java'dan çok daha iyi uygulanır (sonuç olarak en başından itibaren) Birçok, belki de tüm .net çözümleri yalnızca özelliklerde çalışır. WPF, ASPX ve daha fazlası.
Jacek Cz

3

Özellikler ve Alanlar, çoğu durumda benzer görünebilir, ancak değildir. Alanlar için varolmayan özelliklerle ilgili sınırlamalar vardır veya bunun tersi de geçerlidir.

Diğerlerinin de belirttiği gibi. Bir mülkü erişimci özel yaparak salt okunur veya salt yazılır yapabilirsiniz. Bunu bir alanla yapamazsın. Özellikler sanal olabilirken alanlar da olamaz.

Özellikleri getXXX () / setXXX () işlevleri için sözdizimsel şeker olarak düşünün. Perde arkasında bu şekilde uygulanırlar.


1

Alanlar ve özellikler arasında önemli bir fark daha vardır.

WPF kullanırken, yalnızca genel mülklere bağlanabilirsiniz. Bir kamu alanına bağlanması olacaktır değil çalışır. Bu, uygulanmadığınız zamanlarda bile geçerlidir INotifyPropertyChanged(her zaman yapmanız gerekir).


DRY için iyi;) ama bir kez daha yazıyorum, C # dilinde özelliğin güçlü rolünü seviyorum. Java'dan çok daha iyi uygulanır (sonuç olarak en başından itibaren) Birçok, belki de tüm .net çözümleri yalnızca özelliklerde çalışır. WPF, ASPX ve daha fazlası.
Jacek Cz

1

Diğer cevaplar ve örnekler arasında, bu örneğin bazı durumlarda yararlı olduğunu düşünüyorum.

Örneğin, aşağıdakine benzer bir durumunuz olduğunu varsayalım:OnChange property

public Action OnChange { get; set; }

Eğer kullanım delegelere istiyorsanız bunu değiştirmek için gerekenden daha OnChangeiçin fieldbu gibi:

public event Action OnChange = delegate {};

Bu gibi durumlarda alanımızı istenmeyen erişim veya değişikliklere karşı koruruz.


0

Ortak alanlar için her zaman alanlar yerine özellikler kullanmalısınız. Bu, kitaplığınızın gelecekte gerekli olması durumunda mevcut kodları kırmadan herhangi bir alan için kapsülleme yeteneğine sahip olmasını sağlar. Alanları varolan kitaplıklardaki özelliklerle değiştirirseniz, kitaplığınızı kullanan bağımlı modüllerin de yeniden oluşturulması gerekir.


"her zaman" zor bir kelimeyi ifade eder. C # (Java daha iyi) özelliği güçlü bir konuma sahiptir, (muhtemelen istisnasız) ana / ASP, WPF ve diğerleri "bağlama" yöntemidir. Ama yine de, hiçbir varlık mülkiyet duygusu (bazen) ile tasarım hayal edebiliyorum
Jacek Cz
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.