2008-10-15 50 views
19

有很多的建議,你不應該公開地暴露你的領域,而是使用普通的屬性。我通過&結束了。有瑣碎的屬性曾經保存你的培根?

我理解的論據,但I don't think it's good advice in most cases

有沒有人有一個真正重要的時間的例子?當寫一個微不足道的財產在將來有可能變得重要時(或者當失敗時會讓他們陷入真正的麻煩)?

編輯:DataBinding參數是正確的,但不是很有趣。這是DataBinding代碼中的一個錯誤,它不會接受公共字段。因此,我們必須編寫屬性來解決該錯誤,而不是因爲屬性是明智的類設計選擇。

編輯:爲了清楚,我正在尋找現實世界的例子,而不是理論。一個真正重要的時刻。

編輯:在setter上設置斷點的能力似乎很有價值。爲調試器設計我的代碼是不幸的:我寧願調試器變得更聰明,但考慮到我們有調試器,我會採取這種能力。好東西。

+0

中@JasonBunting您的評論感嘆不可變的類型和只讀。我很好奇爲什麼你不能通過 MyProperty {get;私人設置; }? – 2008-10-16 09:43:23

+0

@Robert:因爲我沒有得到免費的驗證,認爲我的實現沒有修改狀態。 – 2008-10-16 15:24:46

+1

如果您不信任自己,請使用後臺字段並編寫單元測試。 私有隻讀字符串名稱; public string Name {get {return name; }} 「屬性或索引」 ......名稱」不能被分配到 - 它是隻讀 – 2008-10-16 20:36:57

回答

25

在一個不確定的未來可能很難使代碼工作,但這不是懶惰的藉口。在字段上編碼屬性是慣例,它是務實的。稱之爲防禦性編程。

其他人也會抱怨說有速度問題,但JIT'er足夠聰明,可以讓它快速曝光公共領域。足夠快,我永遠不會注意到。

一些浮現在腦海中不平凡的事情

  1. 公共區域是完全公開的,你不能強加只讀或只寫語義
  2. 屬性可以有具有不同getset可訪問性(例如,公開獲取,內部設置)
  3. 您無法覆蓋某個字段,但可以擁有虛擬屬性。
  4. 您的班級無法控制公共區域
  5. 您的班級可以控制該屬性。它可以將設置限制爲允許的值範圍,標記狀態已更改,甚至延遲加載該值。
  6. 反射語義不同。公共領域不是財產。
  7. 沒有數據綁定,正如其他人指出的那樣。 (這只是一個錯誤 - 我可以理解爲什麼.net框架設計者不支持他們不贊成的模式)
  8. 你不能在一個接口上放置一個字段,但你可以把一個屬性放在一個接口。
  9. 你的財產甚至不需要存儲數據。您可以創建一個門面並分派給一個包含的對象。

您只需輸入一個13個字符的正確性。這似乎不像投機一般。存在語義上的差異,如果沒有別的,一個屬性具有不同的語義含義,並且比公共領域更加靈活。

public string Name { get; set; } 
public string name; 

我記得當第一次使用.NET我編寫了幾類作爲剛剛字段,然後我需要讓他們成爲某種原因的屬性有一次,當我可以那是浪費時間第一次就做對了。

那麼你有什麼理由爲而不是以下約定?你爲什麼覺得需要游泳?沒有這樣做,它爲你節省了什麼?

10

這個想法的一部分是,這些屬性在未來可能不是微不足道的 - 如果你將外部代碼綁定到一個字段,並且以後想要將它包裝在一個屬性中,所有的相關代碼將不得不改變,而你可能無法做到這一點,尤其是在您是控制設計人員或者無法控制的庫等情況下。

更不用說有某些.NET操作不允許您使用一個領域 - 數據綁定特別。

我相信還有其他很好的理由。爲什麼這對你很重要?使用自動屬性並完成它。似乎不值得關注我的東西...

+0

數據綁定已損壞。吮吸。猜猜我必須處理這個問題。 自動屬性不允許「只讀」,使得穩定的類型有點困難。 我希望我的房產能像站着說:「小心!這不僅僅是數據!」 – 2008-10-15 17:54:06

+0

你可以使用私人設置來自動設置屬性,這可以讓你成爲那裏的一部分。 – 2008-10-15 17:56:41

11

我曾經想過同樣的事情,傑伊。爲什麼要使用一個財產,如果它只是在那裏提供直接訪問私人會員?如果你可以把它描述成一個自動屬性,那麼擁有一個屬性而不是一個屬性就顯得很愚蠢。即使你需要改變實現,你以後可以隨時重構一個真實的屬性,任何相關的代碼仍然可以工作,對吧?好吧,也許不是。

你看,我最近看到了輕微的屬性,所以也許現在我可以幫你做同樣的事情。

什麼終於說服了我是相當明顯的點(回想起來),在.NET屬性僅供getter和setter方法的語法糖,這些方法具有從屬性本身不同的名稱。無論如何,在同一個程序集中的代碼仍然可以工作,因爲你必須同時重新編譯它。但是,如果將某個字段重構爲某個屬性,除非它同時針對新版本重新編譯,否則鏈接到您的其他程序集中的任何代碼將會失敗。如果從一開始就是財產,一切都還是不錯的。

+1

你可以重建其他程序集嗎?如果是,那麼你沒有問題。如果不是,你的徽章要大得多。 http://stackoverflow.com/questions/174198/c35-automatic-properties-why-not-access-the-field-directly#205567 – 2008-10-15 17:47:44

+0

如果你的代碼是一個商業類庫和您從公共領域性質的變化,你可能真的會激怒你的顧客。 – BlackWasp 2008-10-15 22:16:32

+0

@BlackWasp:這是理論,但你有沒有真的需要這樣做?而不需要進行其他重大更改?當二進制兼容性是一個要求? – 2008-10-16 15:26:40

1

我曾經有一個字段,我想從項目中允許統計程序(TotalItems和SuccessfulItems)的窗口暴露。

後來我決定在窗體上顯示統計信息,並且能夠在setter中添加一個調用,以便在屬性更改時更新顯示。

13

我有一個微不足道的屬性,調試時省了幾次。 .Net不支持數據中斷點的概念(讀或寫)。偶爾,在調試一個非常複雜的場景時,跟蹤對特定屬性的讀/寫操作非常重要。這是一個財產容易,但不可能與一個領域。

如果您不在生產環境中工作,爲調試目的重構字段 - >屬性非常簡單。偶爾你會遇到只能在生產環境中複製的錯誤,而這種錯誤很難用新的二進制文件修補。一個屬性可以將你保存在這裏。

雖然這是一個相當有限的情況。

3

如果調用包含屬性訪問器的字段的問題,則更容易調試。在訪問器中放置斷點可以很快幫助找到重入性和其他可能無法捕獲的問題。通過訪問者編組所有對該字段的訪問,您可以確切地確定誰在更改什麼和何時。

2

在.NET中,根據我的理解,你不能將數據綁定到公共字段;但僅限於屬性。因此,如果你想做數據綁定,你別無選擇。

1

很明顯,如果你沒有創建一個共享類庫,並且你沒有使用DataBinding,那麼使用字段將不會引起任何問題。

但是,如果你要創建一個共享的類庫,你會愚蠢恕我直言,否則做多遵循的準則,對於通常的原因有三:

  • 消費者共享類庫可能希望使用DataBinding。

  • 您的共享類的使用者可能需要二進制兼容性,如果您從字段切換到屬性,這是不可能的。

  • 最令人驚訝的原因意味着您應該與其他共享類庫(包括.NET Framework本身)保持一致。

0

恕我直言,沒有這樣的事情,因爲人們一直稱他們爲瑣碎的財產。通過數據綁定等工作方式,微軟已經暗示,任何屬於對象公共接口一部分的數據都應該是屬性。我認爲他們的意思不僅僅是爲了像其他一些語言中的慣例,其中屬性語法更多地是關於約定和便利。

一個更有趣的問題可能是:「我什麼時候應該使用公共領域而不是財產」,或者「當公共領域而不是公共領域保存您的培根?

10

我會用另一個回答你的問題:你有沒有真正從沒有讓你所有的類型和成員公開?我懷疑這樣做並沒有直接阻止任何錯誤。然而,我已經正確地封裝了我的類型,只揭露了要暴露的內容。屬性是相似的 - 優秀的設計比其他任何東西都多。我認爲屬性在概念上與田野不同,它們是合同的一部分,而不是實施的基本組成部分。將它們視爲屬性而不是字段可以幫助我更清晰地思考我的設計,從而導致更好的代碼。

噢,我偶爾從不破壞源代碼兼容性,能夠設置斷點,登錄訪問等方面受益匪淺。

0

具有結構類型的字段允許直接訪問其成員,而這種類型的屬性則不能。因此,如果Thing.BozPoint類型的字段,那麼想要修改其值X值的代碼可以簡單地說是Thing.Boz.X += 5;;如果Thing.Boz是可變屬性,則有必要使用var tmp = Thing.Boz; tmp.X += 5; Thing.Boz = tmp;。用暴露的字段更乾淨地寫東西的能力通常是,但不總是,這是一種祝福。

如果Boz始終可能是一個字段,直接修改其成員會比將其複製到臨時變量,修改它並將其複製回來更乾淨,更快速,更好。如果Boz類型直接暴露了其可變域(如結構應),而不是在瑣碎的包裝紙包裹其中,它也將有可能使用之類的東西Interlocked方法對它們 - 這簡直是不可能的性能。以這種方式使用字段實際上只有一個缺點:如果有必要用屬性替換字段,那麼依賴字段的代碼將會中斷,並且可能很難修復。

簡而言之,我認爲在不關心能夠在不需要重新編譯任何消費者的情況下交換不同版本的代碼的情況下,使用屬性而不是字段的最大效果是防止消費者來自編寫代碼的代碼將利用(並且依賴)具有結構類型的暴露字段的語義。

順便提及,到露出的結構類型的字段的替代方案將是暴露一個ActOnXXX方法。例如:

delegate void ActionByRef<T1>(ref T1 p1); 
delegate void ActionByRef<T1,T2>(ref T1 p1, ref T2 p2); 
delegate void ActionByRef<T1,T2,T3>(ref T1 p1, ref T2 p2, ref T3 p3); 
// Method within the type that defines property `Boz` 
void ActOnBoz<T1>(ActionByRef<Point, T1> proc, ref T1 p1) 
{ 
    proc(ref _Boz, ref p1); // _Boz is the private backing field 
} 

守則,想增加一些局部變量qThing.Boz.X可以打電話Thing.ActOnBoz((ref Point pt, ref int x) => {pt.X += x;}, ref q);,並有行動直接Thing._Boz執行,即使該字段不被暴露。