C # 'da Özellikler kullanmaktan neden kaçınmalıyım?


102

Jeffrey Richter, CLR Via C # adlı mükemmel kitabında mülkleri sevmediğini ve kullanılmamasını tavsiye ettiğini söyledi. Bir sebep gösterdi ama gerçekten anlamıyorum. Biri bana neden mülkleri kullanıp kullanmamam gerektiğini açıklayabilir mi? Otomatik özelliklerle C # 3.0'da bu değişir mi?

Referans olarak Jeffrey Richter'in görüşlerini ekledim:

• Bir özellik salt okunur veya salt okunur olabilir; alan erişimi her zaman okunabilir ve yazılabilir. Bir özellik tanımlarsanız, en iyisi hem alma hem de erişimci ayarlama yöntemlerini sunmaktır.

• Bir özellik yöntemi bir istisna oluşturabilir; alan erişimi asla bir istisna atmaz.

• Bir özellik, bir yönteme out veya ref parametresi olarak aktarılamaz; bir alan olabilir. Örneğin, aşağıdaki kod derlenmeyecektir:

using System;
public sealed class SomeType
{
   private static String Name 
   {
     get { return null; }
     set {}
   }
   static void MethodWithOutParam(out String n) { n = null; }
   public static void Main()
   {
      // For the line of code below, the C# compiler emits the following:
      // error CS0206: A property or indexer may not
      // be passed as an out or ref parameter
      MethodWithOutParam(out Name);
   }
}

• Bir özellik yönteminin yürütülmesi uzun zaman alabilir; alan erişimi her zaman hemen tamamlanır. Özelliklerin kullanılmasının yaygın bir nedeni, iş parçacığını sonsuza kadar durdurabilen iş parçacığı eşitlemesi yapmaktır ve bu nedenle, iş parçacığı eşitlemesi gerekiyorsa bir özellik kullanılmamalıdır. Bu durumda bir yöntem tercih edilir. Ayrıca, sınıfınıza uzaktan erişilebiliyorsa (örneğin, sınıfınız System.MashalByRefObject öğesinden türetilmişse), özellik yöntemini çağırmak çok yavaş olacaktır ve bu nedenle, bir özelliğe bir yöntem tercih edilir. Benim düşünceme göre, MarshalByRefObject'den türetilen sınıflar asla özellikleri kullanmamalıdır.

• Bir satırda birden çok kez çağrılırsa, bir özellik yöntemi her seferinde farklı bir değer döndürebilir; bir alan her seferinde aynı değeri döndürür. System.DateTime sınıfı, geçerli tarih ve saati döndüren salt okunur bir Now özelliğine sahiptir. Bu özelliği her sorguladığınızda, farklı bir değer döndürür. Bu bir hatadır ve Microsoft, Now'ı bir özellik yerine bir yöntem yaparak sınıfı düzeltebilmelerini ister.

• Bir özellik yöntemi, gözlenebilir yan etkilere neden olabilir; alan erişimi asla yapmaz. Başka bir deyişle, bir türden bir kullanıcı, bir tür tarafından tanımlanan çeşitli özellikleri, türdeki herhangi bir farklı davranışı fark etmeden seçtiği herhangi bir sırada ayarlayabilmelidir.

• Bir özellik yöntemi ek bellek gerektirebilir veya aslında nesnenin durumunun parçası olmayan bir şeye bir referans döndürebilir, bu nedenle döndürülen nesneyi değiştirmenin orijinal nesne üzerinde hiçbir etkisi olmaz; bir alanı sorgulamak, her zaman orijinal nesnenin durumunun bir parçası olduğu garanti edilen bir nesneye bir başvuru döndürür. Bir kopya döndüren bir özellikle çalışmak, geliştiriciler için çok kafa karıştırıcı olabilir ve bu özellik genellikle belgelenmez.


11
'C # aracılığıyla CLR'nin 3. baskısına sahibim ve 242. sayfada Bay Richter mülkleri kişisel olarak sevmediğini ancak kullanılmamasını asla önermediğini söylüyor. Lütfen bunu okuduğunuz yerde kitap sürümünü ve sayfa numarasını belirtin.
kirk.burleson

Yanıtlar:


173

Jeff'in mülkleri beğenmemesinin nedeni, alan gibi görünmeleridir - bu nedenle, farkı anlamayan geliştiriciler, onları yürütmek için ucuz olacaklarını varsayarak, alan gibi davranacaklardır.

Şahsen ben bu noktada onunla aynı fikirde değilim - özelliklerin, istemci kodunu eşdeğer yöntem çağrılarına göre daha kolay okunmasını sağladığını görüyorum. Geliştiricilerin, özelliklerin temelde gizli yöntemler olduğunu bilmeleri gerektiğine katılıyorum - ancak geliştiricileri bu konuda eğitmenin, yöntemleri kullanarak kodu okumayı zorlaştırmaktan daha iyi olduğunu düşünüyorum. (Özellikle, aynı ifadede birkaç alıcı ve ayarlayıcının çağrıldığı Java koduna sahip olduğumdan, eşdeğer C # kodunun okunmasının çok daha kolay olacağını biliyorum. Demeter Yasası teoride foo.Name.Lengthçok iyidir , ancak bazen gerçekten kullanmak için doğru şey ...)

(Ve hayır, otomatik olarak uygulanan özellikler bunların hiçbirini gerçekten değiştirmez.)

Bu biraz uzatma yöntemlerinin kullanılmasına karşı olan argümanlara benziyor - mantığını anlayabiliyorum, ancak pratik fayda (az kullanıldığında) benim görüşüme göre dezavantajından ağır basmaktadır.


Cevabınız için çok teşekkürler! Uzantı yöntemlerinin kullanılmasına karşı argümanlar hakkında: Jeffrey Richter'in bazı konularından mı yoksa soyut olarak mı bahsediyorsunuz?
abatishchev

@abatishchev: Uzatma yöntemleri hakkında sadece genel bir noktaydı. Doğrudan mülklerle ilgili değildir.
Jon Skeet

Daha ileri gideceğim. Performans yönü dışında, bir programcının bir şeyin bir alan veya bir mülk olduğunu neden BİLMESİ gerektiğini anlamıyorum. Bunu, nesne örneğinin DURUMUNU belirten bir örnek özniteliği olarak düşünmelidir ve nesne uygulaması, durumundaki tüm değişiklikleri (sınıfın sözleşmesi dahilinde) dikkate almalıdır. Dolayısıyla, sınıfın uygulamasının yeniden tasarımı yapılırsa, özellikler bazı durumlarda alan olabilir veya diğerlerinde alan olabilir. Daha sonra, bir tarla veya bir mülk arasında karar vermek, devletin tutarlı kalmak için ne kadar korumaya ihtiyaç duyduğuyla ilgilidir.
TheBlastOne

1
@PatrickFromberg: Görünüşe göre salt okunur alanları kullanan büyük miktarda kodu kaçırdınız. Özelliklerin değişkenliği ifade ettiğini söyleyecek hiçbir şey yok. Genellikle salt okunur özellikleri destekleyen salt okunur alanlarım olur - bunun kötü bir şey olduğunu mu düşünüyorsunuz?
Jon Skeet

1
@Patrick: Hayır, API'yi uygulamadan ayırmanın faydasını getirir - daha sonra özelliğin alandan nasıl hesaplandığını değiştirebilirsiniz (örneğin, bir alandan iki ilgili özelliği hesaplamak için).
Jon Skeet

34

Peki, argümanlarını tek tek ele alalım:

Bir özellik salt okunur veya salt yazılabilir olabilir; alan erişimi her zaman okunabilir ve yazılabilir.

Erişim üzerinde daha ayrıntılı bir denetime sahip olduğunuz için bu, mülkler için bir kazançtır.

Bir özellik yöntemi bir istisna oluşturabilir; alan erişimi asla bir istisna atmaz.

Bu çoğunlukla doğru olsa da, başlatılmamış bir nesne alanında bir yöntemi çok iyi çağırabilir ve bir istisna atabilirsiniz.

• Bir özellik, bir yönteme out veya ref parametresi olarak aktarılamaz; bir alan olabilir.

Adil.

• Bir özellik yönteminin yürütülmesi uzun zaman alabilir; alan erişimi her zaman hemen tamamlanır.

Ayrıca çok az zaman alabilir.

• Bir satırda birden çok kez çağrılırsa, bir özellik yöntemi her seferinde farklı bir değer döndürebilir; bir alan her seferinde aynı değeri döndürür.

Doğru değil. Alanın değerinin değişmediğini nasıl anlarsınız (muhtemelen başka bir iş parçacığı tarafından)?

System.DateTime sınıfı, geçerli tarih ve saati döndüren salt okunur bir Now özelliğine sahiptir. Bu özelliği her sorguladığınızda, farklı bir değer döndürür. Bu bir hatadır ve Microsoft, Now'ı bir özellik yerine bir yöntem yaparak sınıfı düzeltebilmelerini diler.

Eğer bir hata ise, küçük bir hatadır.

• Bir özellik yöntemi, gözlenebilir yan etkilere neden olabilir; alan erişimi asla yapmaz. Başka bir deyişle, bir türden bir kullanıcı, bir tür tarafından tanımlanan çeşitli özellikleri, türdeki herhangi bir farklı davranışı fark etmeden seçtiği herhangi bir sırada ayarlayabilmelidir.

Adil.

• Bir özellik yöntemi ek bellek gerektirebilir veya aslında nesnenin durumunun parçası olmayan bir şeye bir referans döndürebilir, bu nedenle döndürülen nesneyi değiştirmenin orijinal nesne üzerinde hiçbir etkisi olmaz; bir alanı sorgulamak, her zaman orijinal nesnenin durumunun bir parçası olduğu garanti edilen bir nesneye bir başvuru döndürür. Bir kopya döndüren bir özellikle çalışmak, geliştiriciler için çok kafa karıştırıcı olabilir ve bu özellik genellikle belgelenmez.

Protestoların çoğu Java'nın alıcıları ve ayarlayıcıları için de söylenebilirdi - ve pratikte bu tür problemler olmadan uzunca bir süre uyguladık.

Bence sorunların çoğu, daha iyi sözdizimi vurgulayarak (yani özellikleri alanlardan ayırarak) çözülebilir, böylece programcı ne bekleyeceğini bilir.


3
"sorunlar daha iyi sözdizimi vurgulayarak çözülebilir" : Genel alanları ne sıklıkla kullanıyorsunuz? Özel alanlar genellikle farklı bir stile sahiptir, örn _field. Ya da sadece küçük harf field.
Steven Jeuris

18

Kitabı okumadım ve anlamadığın kısmından alıntı yapmadın, bu yüzden tahmin etmem gerekecek.

Bazı insanlar mülkleri sevmez çünkü kodunuzun şaşırtıcı şeyler yapmasını sağlayabilirler.

Eğer yazarsam Foo.Bar yazarsam, onu okuyan insanlar normalde bunun Foo sınıfının bir üye alanına erişmesini bekleyeceklerdir. Ucuz, neredeyse ücretsiz bir işlem ve belirleyicidir. Tekrar tekrar arayabilirim ve her seferinde aynı sonucu alabilirim.

Bunun yerine, özelliklerle, aslında bir işlev çağrısı olabilir. Sonsuz bir döngü olabilir. Bir veritabanı bağlantısı açabilir. Her eriştiğimde farklı değerler döndürebilir.

Linus'un neden C ++ 'dan nefret ettiğine benzer bir argüman. Kodunuz okuyucuya şaşırtıcı gelebilir. Operatörün aşırı yüklenmesinden nefret eder: a + bille de basit ekleme anlamına gelmez. Tıpkı C # özellikleri gibi oldukça karmaşık bir işlem anlamına gelebilir. Yan etkileri olabilir. Her şeyi yapabilir.

Dürüst olmak gerekirse, bunun zayıf bir argüman olduğunu düşünüyorum. Her iki dil de bunun gibi şeylerle doludur. (C # 'ta da operatörün aşırı yüklenmesinden kaçınmalı mıyız? Sonuçta, aynı argüman orada da kullanılabilir)

Özellikler soyutlamaya izin verir. Bir şeyin normal bir alan olduğunu varsayabilir ve onu tek bir alanmış gibi kullanabiliriz ve perde arkasında neler olduğu konusunda endişelenmemize gerek kalmaz.

Bu genellikle iyi bir şey olarak kabul edilir, ancak açıkça programcının anlamlı soyutlamalar yazmasına dayanır. Kişisel özellikleri olmalıdır alanları gibi davranır. Yan etkileri olmamalı, pahalı veya güvenli olmayan işlemler yapmamalıdırlar. Onları alan olarak düşünebilmek istiyoruz .

Ancak, onları mükemmelden daha az bulmam için başka bir nedenim var. Diğer işlevlere referansla aktarılamazlar.

Alanlar, refçağrılan bir işleve doğrudan erişmesine izin verecek şekilde geçirilebilir . İşlevler, çağrılan bir işlevin doğrudan erişmesine izin vererek delege olarak aktarılabilir.

Özellikler ... olamaz.

Bu berbat.

Ancak bu, mülklerin kötü olduğu veya kullanılmaması gerektiği anlamına gelmez. Birçok amaç için harikalar.


3
Benim argümanım, bunun bir alan olduğunu varsaymamalısınız - çünkü onu başka bir sınıftan çağırıyorsanız, sabit olmayan alanlara erişiminiz olmamalıdır, çünkü bunlar özel olmalıdır. (Ayrıca sizi bilgilendirmek için bir adlandırma kuralı var.)
Jon Skeet

1
Evet katılıyorum. Argüman, "Bu sözdiziminin yalnızca alanlar için kullanılmasına alışkınım. Bu nedenle, onu diğer durumları kapsayacak şekilde genişletmek kötü" şeklinde özetlenebilir. Ve apaçık cevap "Pekala, o zaman diğer davaları kapatmaya alış ve fena olmayacak". ;)
jalf

Keşke .net dilleri, bir sınıfın özellikleri param olarak göstermesi için standart bir yol refsağlasın; bir parçası (örneğin, Foobir formu) void Foo<T>(ActionByRef<Point,T> proc, ref T param)özel bir niteliği ile ve derleyici dönüşüm sahip thing.Foo.X+=someVar;olarak Foo((ref Point it, ref int param)=>it.X += param, ref someVar);. Lambda statik bir temsilci olduğu için, herhangi bir kapatma gerekmeyecektir ve bir nesnenin kullanıcısı, özelliği gerçek bir refparametre olarak yedekleyen herhangi bir depolama konumunu kullanabilir (ve bunu bir refparametre olarak diğer yöntemlere geçirebilir ).
supercat

Lambda'yı elle yazmak gerçekten iğrenç görünen kaynak kodu üretir, ancak bu nedenle derleyicinin dönüşümü gerçekleştirmesi yararlı olacaktır. Bir sınıfın "ref-by-ref" özelliğini ifşa etme kodu oldukça makul olacaktır. Kod, arayan tarafında sadece çirkin (dönüşüm yok).
süper otomobil

Lütfen bir özelliğin üye olarak gizlenmiş bir işlev çağrısı olduğunu anlayın, bu nedenle bir sınıfın genel işlevlerini iletebildiğinizden daha fazla referansla aktarılamaz. Bu şekilde yapmak istiyorsanız her zaman genel üyeyi kullanabilirsiniz. Bir özellik akıllı bir üyedir, sete geçirilen geçersiz veriler için bir istisna atabilir.
Diceyus

17

2009'da, bu tavsiye sadece Peynirimi Kim Taşıdı ? çeşidinin . Bugün, neredeyse gülünç derecede modası geçmiş.

Pek çok yanıtın parmak uçlarında olduğu, ancak tam olarak ele alınmadığı çok önemli bir nokta, özelliklerin bu sözde "tehlikelerinin" çerçeve tasarımının kasıtlı bir parçası olduğudur!

Evet, özellikler şunları yapabilir:

  • Alıcı ve ayarlayıcı için farklı erişim değiştiricileri belirtin. Bu, tarlalara göre bir avantajdır . Ortak bir model, yalnızca alanlarla elde edilemeyen çok yararlı bir kalıtım tekniği olan, halka açık bir alıcıya ve korumalı veya dahili bir ayarlayıcıya sahip olmaktır .

  • Bir istisna atın. Bugüne kadar bu, özellikle veri bağlama konseptlerini içeren UI çerçeveleriyle çalışırken en etkili doğrulama yöntemlerinden biri olmaya devam ediyor. Alanlarla çalışırken bir nesnenin geçerli durumda kalmasını sağlamak çok daha zordur.

  • Yürütmek için uzun zaman ayırın. Buradaki geçerli karşılaştırma , eşit derecede uzun alan değil, yöntemlerle yapılır . Bir yazarın kişisel tercihi dışında "bir yöntem tercih edilir" ifadesine dayanak verilmemiştir.

  • Sonraki çalıştırmalarda alıcısından farklı değerler döndürür. Bu, ref/ outparametrelerinin erdemlerini alanlarla öven noktaya çok yakın bir şaka gibi görünüyor , bir alanın değeri a ref/out çağrısından değerinin önceki değerinden farklı olacağı garantili ve tahmin edilemeyen bir şekilde.

    Afferent bağlaşımları olmayan tek iş parçacıklı erişimin spesifik (ve pratik olarak akademik) durumundan bahsediyorsak , görünür durumu değiştiren yan etkilere sahip olmanın kötü bir özellik tasarımı olduğu oldukça iyi anlaşılmıştır ve belki de benim hafızam soluyor, ancak kullananların herhangi bir örneğini hatırlayamıyorumDateTime.Now aynı değeri ve her seferinde ortaya çıkmasını bekleyen . En azından bir varsayımla bu kadar kötü bir şekilde mahvetmeyecekleri herhangi bir örnek DateTime.Now().

  • Gözlenebilir yan etkilere neden olur - ki bu, özelliklerin ilk etapta bir dil özelliği olarak icat edilmesinin nedeni de budur. Microsoft'un kendi Mülk Tasarımı yönergeleri, ayarlayıcı sırasının önemli olmaması gerektiğini, aksi takdirde geçici birleşme anlamına geleceğini belirtir . Elbette, yalnızca alanlarla zamansal birleşme elde edemezsiniz, ancak bunun nedeni, bir yöntem uygulanana kadar, yalnızca alanlarla hiçbir anlamlı davranışa neden olamazsınız.

    Özellik erişimcileri, herhangi bir işlem yapılmadan önce nesneyi geçerli bir duruma zorlayarak belirli türlerdeki zamansal eşleşmelerin önlenmesine yardımcı olabilir - örneğin, bir sınıfın bir StartDateve bir varsa EndDate, daha sonra da geri zorlamadan EndDateönce ayarlayarak . Bu, olay güdümlü kullanıcı arabiriminin bariz örneği dahil olmak üzere çok iş parçacıklı veya eşzamansız ortamlarda bile geçerlidir.StartDateStartDate

Alanların dahil edemeyeceği özelliklerin yapabileceği diğer şeyler:

  • Başlatma sırası hatalarını önlemenin en etkili yollarından biri yavaş yükleme .
  • MVVM mimarisinin temelini hemen hemen oluşturan Değişiklik Bildirimleri .
  • Kalıtım , örneğin bir özetin tanımlanması TypeveyaName bu şekilde türetilmiş sınıfları kendileri hakkında ilginç ama yine de sabit meta veriler sağlayabilir.
  • KesişmeYukarıdakiler sayesinde .
  • Dizinleyiciler hiç COM birlikte ve kaçınılmaz çıktısının ile çalışmak zorunda kaldığı herkes,Item(i) harika bir şey olarak tanıyacaktır aramalar.
  • Tasarımcılar ve genel olarak XAML çerçeveleri oluşturmak için gerekli olan PropertyDescriptor ile çalışın .

Richter açıkça üretken bir yazar ve CLR ve C # hakkında çok şey biliyor, ancak söylemeliyim ki, bu tavsiyeyi ilk yazdığı zamana benziyor (daha son revizyonlarında olup olmadığından emin değilim - içtenlikle umuyorum) eski alışkanlıklarını bırakmak istemediğini ve C # kurallarını kabul etmekte zorlandığını (örneğin C ++ 'ya karşı).

Bununla kastettiğim, onun "zararlı kabul edilen özellikler" argümanı esasen tek bir ifadeye indirgeniyor: Özellikler alan gibi görünür, ancak alan gibi davranmayabilirler. Ve ifadeyle ilgili sorun, doğru olmaması veya en iyi ihtimalle oldukça yanıltıcı olmasıdır. Özellikler yok alanları gibi bakmak - en azından onlar değil sözde alanlara benzemeye.

C #'da diğer CLR dilleri tarafından paylaşılan benzer kurallara sahip iki çok güçlü kodlama kuralı vardır ve bunları takip etmezseniz FXCop size bağırır:

  1. Alanlar her zaman özel olmalı , asla halka açık olmamalıdır .
  2. Alanlar camelCase'de belirtilmelidir. Özellikler PascalCase'dir.

Bu nedenle, Foo.Bar = 42bir özellik erişimcisi mi yoksa bir alan erişimcisi mi olduğu konusunda belirsizlik yoktur . Bu bir özellik erişimcisidir ve diğer herhangi bir yöntem gibi ele alınmalıdır - yavaş olabilir, bir istisna atabilir, vb. Soyutlamanın doğası budur - nasıl tepki verileceği tamamen beyan eden sınıfın takdirine bağlıdır. Sınıf tasarımcıları en az sürpriz ilkesini uygulamalı, ancak arayanlar bir özellik hakkında, teneke üzerinde yazdığı şeyi yapması dışında hiçbir şey varsaymamalı. Bu kasıtlı.

Özelliklerin alternatifi, her yerde alıcı / ayarlayıcı yöntemleridir. Java yaklaşımı bu ve başından beri tartışmalı bir konu . Bu sizin çantanızsa sorun değil, ama biz .NET kampında nasıl olduğumuz değil. En azından statik olarak yazılmış bir sistemin sınırları içinde, Fowler'ın Sözdizimsel Gürültü dediği şeyden kaçınmaya çalışıyoruz . Ekstra parantezler, ekstra get/ setsiğiller veya ekstra yöntem imzaları istemiyoruz - eğer netlik kaybı olmadan bunlardan kaçınabiliyorsak.

Ne istersen söyle, ama foo.Bar.Baz = quux.Answers[42]her zaman okumaktan çok daha kolay olacak foo.getBar().setBaz(quux.getAnswers().getItem(42)). Ve her gün bunun binlerce satırını okurken fark yaratıyor.

(Ve yukarıdaki paragrafa vereceğiniz doğal yanıt "elbette okumak zordur, ancak birden fazla satıra ayırırsanız daha kolay olur" demekse, özür dilerim ki konuyu tamamen kaçırdınız .)


11

Genel olarak Özellikler'i kullanmamanız için herhangi bir neden göremiyorum.

C # 3 + 'daki otomatik özellikler sadece sözdizimini biraz basitleştirir (la sözdizimi şekeri).


lütfen o kitabın 215-216. sayfalarını okuyun. Eminim Jeffrey Richter'in kim olduğunu biliyorsunuzdur!
Quan Mai

Okudum (C # aracılığıyla CLR, 2. Baskı), onun pozisyonuna katılmıyorum ve gerçek nedenler görmüyorum özellikleri kullanmamak!
abatishchev

İyi bir kitap, ama şu anda yazara katılmıyorum.
Konstantin Tarkus

Yazarın Özellikleri kullanmamayı önerdiği yer tam olarak nerede? S. 215-217'de hiçbir şey bulamadım
Konstantin

Soruma Jeffrey'nin görüşlerini ekledim :). 215-216. Sayfalarda basılı baskıda bulabilirsiniz :)
Quan Mai

9

Bu sadece bir kişinin görüşü. Epeyce c # kitabı okudum ve henüz başka birinin "özellikleri kullanma" dediğini görmedim.

Ben şahsen özelliklerin c # ile ilgili en iyi şeylerden biri olduğunu düşünüyorum. İstediğiniz mekanizma aracılığıyla durumu açığa çıkarmanıza izin verirler. Bir şeyi ilk kez kullandığınızda tembel bir şekilde somutlaştırabilirsiniz ve bir değer belirleme üzerinde doğrulama yapabilirsiniz. Bunları kullanırken ve yazarken, ben sadece özellikleri ayarlayıcılar ve alıcılar olarak düşünüyorum ki bu çok daha hoş bir sözdizimi.

Özellikli uyarılara gelince, bir çift var. Biri muhtemelen mülklerin kötüye kullanılmasıdır, diğeri ince olabilir.

İlk olarak, özellikler yöntem türleridir. Bir özelliğe karmaşık bir mantık yerleştirirseniz şaşırtıcı olabilir çünkü bir sınıfın çoğu kullanıcısı mülkün oldukça hafif olmasını bekler.

Örneğin

public class WorkerUsingMethod
{
   // Explicitly obvious that calculation is being done here
   public int CalculateResult()
   { 
      return ExpensiveLongRunningCalculation();
   }
}

public class WorkerUsingProperty
{
   // Not at all obvious.  Looks like it may just be returning a cached result.
   public int Result
   {
       get { return ExpensiveLongRunningCalculation(); }
   }
}

Bu vakalar için yöntem kullanmanın bir ayrım yapmaya yardımcı olduğunu görüyorum.

İkinci olarak ve daha da önemlisi, hata ayıklama sırasında bunları değerlendirirseniz, özelliklerin yan etkileri olabilir.

Bunun gibi bir mülkünüz olduğunu varsayalım:

public int Result 
{ 
   get 
   { 
       m_numberQueries++; 
       return m_result; 
   } 
}

Şimdi, çok fazla sorgu yapıldığında oluşan bir istisnanız olduğunu varsayalım. Tahmin edin, hata ayıklamaya başladığınızda ve hata ayıklayıcıdaki özelliği devraldığınızda ne olur? Kötü şeyler. Bunu yapmaktan kaçının! Özelliğe bakmak programın durumunu değiştirir.

Sahip olduğum tek uyarılar bunlar. Mülklerin faydalarının sorunlardan çok daha ağır bastığını düşünüyorum.


6

Bu sebep, çok özel bir bağlam içinde verilmiş olmalı. Bu genellikle tam tersidir - size, istemcilerini etkilemeden bir sınıfın davranışını değiştirmenize olanak tanıyan bir soyutlama düzeyi sağladıkları için özellikleri kullanmanız önerilir.


Müşteri ile sınıf mülkü arasındaki "sözleşmenin" önemini dolaylı olarak vurgulamak için +1.
TheBlastOne

6

Jeffrey Richter'in görüşlerinin ayrıntılarını seçmekten kendimi alamıyorum:

Bir özellik salt okunur veya salt yazılabilir olabilir; alan erişimi her zaman okunabilir ve yazılabilir.

Yanlış: Alanlar salt okunur olarak işaretlenebilir, böylece yalnızca nesnenin kurucusu bunlara yazabilir.

Bir özellik yöntemi bir istisna oluşturabilir; alan erişimi asla bir istisna atmaz.

Yanlış: Bir sınıfın uygulanması, bir alanın erişim değiştiricisini genelden özele değiştirebilir. Çalışma zamanında özel alanları okuma girişimleri her zaman bir istisnayla sonuçlanır.


5

Jeffrey Richter'e katılmıyorum, ancak mülkleri neden sevmediğini tahmin edebiliyorum (kitabını okumadım).

Özellikler tıpkı yöntemler gibi (uygulama açısından) olsa da, bir sınıfın kullanıcısı olarak, özelliklerinin genel bir alan gibi "az çok" davranmasını bekliyorum, örneğin:

  • özellik alıcı / ayarlayıcı içinde zaman alıcı bir işlem yoktur
  • özellik alıcının hiçbir yan etkisi yoktur (birden çok kez çağırmak sonucu değiştirmez)

Ne yazık ki bu şekilde davranmayan mülkler gördüm. Ancak sorun mülklerin kendileri değil, onları uygulayan kişilerdir. Yani sadece biraz eğitim gerektiriyor.


1
Temiz bir sözleşmenin önemini vurguladığı için +1. Her referansta düzenli olarak farklı bir değer döndüren görünüşte salt okunur bir özelliğe sahip olmak, bir okuma-yazma özelliğidir - yalnızca kendi değerine değil, diğer örnek değişkenlerine (doğrudan veya dolaylı olarak) yazar. Bu kötü bir tarz değildir, ancak belgelenmelidir (veya sözleşmenin üstü kapalı bir parçası olmalıdır).
TheBlastOne

4

Özellikleri kullanmamayı düşündüğüm bir zaman var ve bu .Net Compact Framework kodunu yazarken. CF JIT derleyicisi, masaüstü JIT derleyicisi ile aynı optimizasyonu gerçekleştirmez ve basit özellik erişimcilerini optimize etmez, bu nedenle bu durumda basit bir özellik eklemek, genel bir alanı kullanmaktan çok az miktarda kod şişmesine neden olur. Genellikle bu bir sorun olmaz, ancak hemen hemen her zaman Compact Framework dünyasında sıkı bellek kısıtlamalarıyla karşı karşıya kalırsınız, bu nedenle bunun gibi küçük tasarruflar bile önemlidir.


4

Bunları kullanmaktan kaçınmamalısınız, ancak diğer katkıda bulunanların gösterdiği nedenlerden dolayı bunları nitelik ve özenle kullanmalısınız.

Bir keresinde, bir veritabanına dahili olarak işlem dışı bir çağrı açan ve müşteri listesini okuyan Müşteriler gibi bir özellik görmüştüm. İstemci kodunda, her yinelemede ve seçilen Müşterinin erişimi için veritabanına ayrı bir çağrıya neden olan 'for (int i to Customer.Count)' vardı. Bu, mülkü çok hafif tutma ilkesini - nadiren dahili alan erişiminden daha fazla - gösteren korkunç bir örnek.

Özellikleri kullanmak için bir argüman, ayarlanan değeri doğrulamanıza izin vermeleridir. Bir diğeri, mülkün değerinin, TotalValue = miktar * miktar gibi tek bir alan değil, türetilmiş bir değer olabileceğidir.


3

Şahsen ben özellikleri sadece basit get / set yöntemleri oluştururken kullanıyorum. Karmaşık veri yapılarına gelince ondan uzaklaşıyorum.


3

Argüman, alanlara benzedikleri için özelliklerin kötü olduğunu varsayar, ancak şaşırtıcı eylemler gerçekleştirebilirler. Bu varsayım, .NET programcılarının beklentileri tarafından geçersiz kılınmıştır:

Özellikler alanlara benzemiyor. Alanlar mülk gibi görünür.

• Bir özellik yöntemi bir istisna oluşturabilir; alan erişimi asla bir istisna atmaz.

Bu nedenle, alan, asla istisna oluşturmayacağı garanti edilen bir mülk gibidir.

• Bir özellik, bir yönteme out veya ref parametresi olarak aktarılamaz; bir alan olabilir.

Dolayısıyla, alan bir özellik gibidir, ancak ek yeteneklere sahiptir: a ref/ outkabul yöntemlerine geçiş.

• Bir özellik yönteminin yürütülmesi uzun zaman alabilir; alan erişimi her zaman hemen tamamlanır. [...]

Yani tarla, hızlı bir mülk gibidir.

• Bir satırda birden çok kez çağrılırsa, bir özellik yöntemi her seferinde farklı bir değer döndürebilir; bir alan her seferinde aynı değeri döndürür. System.DateTime sınıfı, geçerli tarih ve saati döndüren salt okunur bir Now özelliğine sahiptir.

Bu nedenle alan, alan farklı bir değere ayarlanmadıkça aynı değeri döndürmesi garanti edilen bir özellik gibidir.

• Bir özellik yöntemi, gözlenebilir yan etkilere neden olabilir; alan erişimi asla yapmaz.

Yine, bir alan, bunu yapmaması garanti edilen bir özelliktir.

• Bir özellik yöntemi ek bellek gerektirebilir veya aslında nesnenin durumunun parçası olmayan bir şeye bir referans döndürebilir, bu nedenle döndürülen nesneyi değiştirmenin orijinal nesne üzerinde hiçbir etkisi olmaz; bir alanı sorgulamak, her zaman orijinal nesnenin durumunun bir parçası olduğu garanti edilen bir nesneye bir başvuru döndürür. Bir kopya döndüren bir özellikle çalışmak, geliştiriciler için çok kafa karıştırıcı olabilir ve bu özellik genellikle belgelenmez.

Bu şaşırtıcı olabilir, ancak bunu yapan bir özellik olduğu için değil. Daha ziyade, mülklerde neredeyse hiç kimsenin değişken kopyalar döndürmesidir, bu nedenle% 0.1 durumu şaşırtıcıdır.


0

Özellikler yerine yöntemleri çağırmak, çağırılan kodun okunabilirliğini büyük ölçüde azaltır. Örneğin, J # 'da ADO.NET kullanmak bir kabustu çünkü Java özellikleri ve dizinleyicileri (aslında bağımsız değişkenli özelliklerdir) desteklemiyor. Ortaya çıkan kod, her yerde boş parantez yöntem çağrılarıyla son derece çirkindi.

Özellikler ve dizin oluşturucular için destek, C # 'ın Java'ya göre temel avantajlarından biridir.

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.