2010-07-22 119 views
159

我才意識到,在C#屬性結構還可以與私人訪問修飾符使用:是否有任何理由在C#中使用私有屬性?

private string Password { get; set; } 

儘管這在技術上是有趣的,我無法想象我會用它,因爲一個私人領域涉及即使少儀式

private string _password; 

,當我會永遠需要是我無法想象能夠內部得到但不設置設置但不得到私有字段:

private string Password { get; } 

private string Password { set; } 

但也許有一個用例與嵌套/繼承類或可能在哪裏一個get/set可能包含邏輯,而不僅僅是回饋屬性的值,儘管我傾向於保持屬性的嚴格性,並讓顯式方法執行任何邏輯操作。 GetEncodedPassword()

有沒有人在C#中使用私有屬性是出於任何原因,還是僅僅是那些技術上可行但很少使用的實際代碼構造?

附錄

尼斯的答案,通過他們讀我宰殺這些用途爲私人性質:

  • 當私人領域需要延遲加載
  • 當私人領域需要額外的邏輯或計算值
  • 由於專用字段可能難以調試
  • 爲了「向您自己提交合同」
  • 在內部轉換/簡化公開的屬性序列化
  • 包裝全局變量的一部分,你的類
+3

「私人字符串密碼{get;}」甚至不合法的C#。它不會編譯。 – 2010-07-22 15:17:53

+2

@eric true,它會得到錯誤「... Password.get'必須聲明一個實體,因爲它沒有標記爲抽象或外部自動實現的屬性必須同時定義get和set訪問器。我只是假定它會工作,因爲我使用'公共字符串密碼{得到{返回_密碼;經常。 – 2010-07-22 15:30:18

+0

私人財產鼓勵的技術是*自封裝* - 請參閱:http://sourcemaking.com/refactoring/self-encapsulate-field – LBushkin 2010-07-22 18:30:10

回答

151

我使用它們,如果我需要緩存一個值,並希望延遲加載它。

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

     return _password; 
    } 
} 
+0

+1這也是我的標準使用!我還喜歡稍後以@Reed Copsey的方式添加額外邏輯的能力。 – 2010-07-22 15:21:48

+0

+1同樣在這裏... – 2010-07-22 16:36:57

+13

一個很好的常見模式是'return _password ?? (_password = CallExpensiveOperation());' – Marc 2010-07-22 23:20:08

4

內使用我現在然後用它們每一個。當您可以輕鬆地在屬性中放置斷點或者可以添加日誌記錄語句時,它們可以更容易地進行調試。

如果以後需要更改某些數據的類型方式或如果你需要使用反射。

+0

同上;如果在get/set中涉及邏輯,我有時可能會使用私有或受保護的屬性。它通常取決於多少邏輯:我將在屬性中執行簡單的邏輯,我通常會使用輔助函數的很多邏輯。無論代碼如何最可維護。 – TechNeilogy 2010-07-22 14:57:22

32

也許有一個用例的嵌套/繼承的類或者是其中的get/set可能包含的邏輯,而不是隻給後面的屬性值

我個人使用,甚至當我不需要屬性的getter或setter的邏輯。使用屬性即使是私有屬性也可以幫助您確定未來的代碼,以便稍後將邏輯添加到getter中(如果需要)。

如果我覺得一個屬性最終可能需要額外的邏輯,我有時會將它包裝到一個私有屬性中而不是使用一個字段,這樣我就不必在以後更改我的代碼。


在一個半相關的情況下(雖然比你的問題不同),我非常頻繁使用私有制定者的公共屬性:

public string Password 
{ 
    get; 
    private set; 
} 

這給你一個公共的getter,但保持二傳手私人的。

+0

+1有道理:「如果我覺得一個屬性最終可能需要額外的邏輯,我有時會將它包裝到一個私有屬性中,而不是使用一個字段,這樣我就不必稍後更改我的代碼。」 – 2010-07-22 15:00:42

+5

private setters <3 – Earlz 2010-07-22 15:38:51

2

通常的做法是隻使用get/set方法修改成員,甚至是私有成員。現在,背後的邏輯就是讓你知道你的get/set總是以特定的方式行事(例如,引發事件),這似乎沒有道理,因爲這些將不會包含在屬性方案中。但老習慣很難消除。

2

當存在與屬性集合相關的邏輯或獲取(認爲延遲初始化)並且該屬性在類中的一些地方使用時,這是非常有意義的。

如果它只是一個直接的後盾領域?沒有什麼可以成爲一個很好的理由。

11

唯一的一個用法,我能想到的

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

+1爲從其他私有變量計算的有用類屬性 – 2010-07-22 15:43:29

+0

爲什麼不使用私有方法 'private bool IsPasswordSet() { return!String。IsNullOrEmpty(_password); }' – Roman 2016-09-21 16:05:48

5

的屬性和字段是不是一對一的。一個屬性是關於一個類的接口(不管是在談論它的公共接口還是內部接口),而一個屬性是關於類的實現。不應該將屬性視爲暴露字段的方式,它們應該被視爲暴露類的意圖和目的的一種方式。

就像您使用屬性向您的消費者提供關於您班級的組成部分的合同一樣,您也可以出於非常類似的原因向您自己提供合同。所以是的,我確實使用私有財產。有時候私有財產會隱藏實現細節,例如延遲加載,屬性實際上是多個領域和方面的聚合,或者每次調用都需要虛擬實例化財產(認爲DateTime.Now)。在班級的後端,甚至在你自己身上執行這個任務也是有意義的。

+0

+1:「你也可以出於非常類似的原因向你自己提供合同」很有道理 – 2010-07-22 15:11:39

16

懶惰初始化是一個可以整潔的地方,例如,

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; 

然後,你可以寫:​​無處不在,而不是this.mytype.Value和封裝的事實,這是在一個地方懶洋洋地實例化。

有一件令人遺憾的事情是,C#不支持將支持域作爲範圍映射到屬性(即在屬性定義中聲明它)以完全隱藏它並確保它只能通過屬性訪問。

+2

同意它將在那裏有範圍方面。 – 2010-07-22 15:03:01

+5

我經常使用這種相同的技術,我也希望字段可以作用於代碼體。這是一個很好的功能,但優先級低。 – 2010-07-22 15:12:04

+3

@Eric Lippert - 'accessor-declarations'中的'field-declaration'作用域在很長一段時間內在C#願望清單中排名第一。如果你能在一些(實際)未來的版本中得到設計和實現,那麼我會烤你一塊蛋糕。 – 2010-07-22 17:16:54

14

私人獲取唯一屬性的一個很好用法是計算值。有幾次,我有私人只讀的屬性,只是在我的類型的其他領域進行計算。它不值得一種方法,並且對其他類非常感興趣,所以它就是私有財產。

97

這個在我的代碼中的主要用法是延遲初始化,正如其他人提到的。

私有屬性超過字段的另一個原因是私有屬性比專用字段更容易調試。我經常想知道這樣的事情:「這個領域意想不到,誰是第一個設置這個領域的調用者?」如果你可以在setter上放置一個斷點並打開它,它會更容易。你可以把日誌記錄在那裏。你可以把性能指標放在那裏。您可以放入在調試版本中運行的一致性檢查。

基本上,它歸結爲:代碼比數據更強大。任何讓我編寫我需要的代碼的技術都是很好的技術。屬性不允許你在其中編寫代碼。

+4

你說的「代碼比數據更強大嗎?使用Google搜索返回指向您的引用。只是想知道,所以我可以在需要時正確引用它。 – 2011-03-24 18:30:53

+15

@Joan:我不知道。要麼我做了它,要麼我聽到有人說出來,並且想:「哇,我應該完全偷走它,然後忘記我偷走了誰的全部。」 – 2011-03-24 20:04:28

+2

謝謝埃裏克。嗯,我只是相信你,因爲我不想說「匿名報價」:O – 2011-03-24 20:11:09

7

我在序列化中使用它們,例如DataContractSerializer或支持此用法的protobuf-net(XmlSerializer沒有)。如果您需要簡化的對象序列化的一部分,它是有用的:

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

一件事,我做所有的時間是店裏的「全局」變量/緩存到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; 
    } 
} 
4

我用私人性質減少訪問經常使用的子屬性的代碼。

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

如果有許多子屬性,這很有用。

相關問題