2010-12-09 100 views
5

當實現了列表屬性的設置(在C#),它是一個不好的事,可以作爲:目錄的屬性設置

private List<string> _TheList = new List<string>(); 
    public List<string> TheList 
    { 
     get { return _TheList; } 
     set { _TheList = value; } 
    } 

如果它不能寫成:

private List<string> _TheList = new List<string>(); 
    public List<string> TheList 
    { 
     get { return _TheList; } 
     set { _TheList = new List<string>(value); } 
    } 

最多直到今天我通常使用前者,但是最近我發現了一些使用後者的代碼,似乎這可能是實現這一點的正確方法。

不會使用前者會在更改分配給它的外部列表時更改TheList屬性。例如:

List<string> list = new List<string>(); 
list.Add("Hello"); 

var c = new someClass(); 
c.TheList = list; 

使用前將不會在下面的代碼打破的thelist的封裝:

list.Clear(); 

現在c.TheList也是空的,這可能不是我們想要的。但是,使用後一種方法,c.TheList不會被清除。

+0

不,第二種解決方案是不正確的。使用第一個解決方案,如果你想設置一個副本,而不是一個參考 - 寫c.TheList =新列表(列表); – vorrtex 2010-12-09 16:51:52

+1

這取決於你的所有權語義。一些呼叫者可能期望能夠設置列表並且仍然「從外部」更新它。無論你採取哪種方式,都要確保將其適當記錄下來。 – 2010-12-09 16:52:01

+0

感謝所有偉大的答案。我很高興沒有先檢查就沒有開始使用第二種方法。似乎共識是不提供二傳手(在大多數情況下)或至少使其受到保護。 – mikesigs 2010-12-09 17:19:13

回答

7

Collection properties should be readonly

Your property should expose a Collection<T>, not a List<T>

編輯:說明:

如果其他代碼拷貝到列表的引用(例如,var list = Thingy.TheList),它可以得到,如果你的屬性設置爲不同的列表搞砸。 (它最終會持有一個孤兒)
通常,允許人們將屬性指向不同的收集實例的原因很少。

使用Collection<T>而不是List<T>可以攔截對集合的更改並添加驗證或維護父字段。 (通過繼承Collection<T>並覆蓋InsertItem和其他方法)您甚至可以在shippinga庫之後添加這樣的邏輯而不會破壞調用代碼。

+2

或者作爲`ReadOnlyCollection `暴露出來,`List `有一個AsReadOnly()方法可以很容易的做返回。 – pstrjds 2010-12-09 16:53:27

3

這完全取決於你希望你的財產如何運作。如果你想要一份副本,請複製一份。否則,不要。通常情況下,像這樣的屬性根本不會公開一個setter,因爲替換整個列表並不是這種情況下所需的操作。

當然,使用第二種方法可能是一個性能問題,因爲屬性語法隱藏了每次使用setter時都完全複製並創建一個新列表的事實。

0

首先,兩者都有些不正確。公共屬性應該真正暴露爲IList,因爲List是實現特定的(當使用List作爲公共屬性時,fxcop實際上會警告你)。

其次,如果可能的話我會讓setter成爲私人的。使用吸氣劑的用戶仍然可以添加/刪除/清除/等。但是可以簡化您在問題中提出的問題。

6

我相信既然一個列表是一個引用對象,你所需要做的就是獲得引用。所以:

private List<string> _TheList = new List<string>(); 
public List<string> TheList 
{ 
    get { return _TheList; } 
} 

一旦你的參考,並更改集合,你改變_TheList

0

我不認爲這是一個普遍的回答你的問題。你描述的行爲可能會或可能不是你想要的。

總的來說,我與SLaks同意這是清潔只讀保持集合的屬性,但是這一切都取決於

0

我不知道我理解正確。但我這樣做:

c.TheList = list.ToArray().ToList();