你如何公開一個集合完全取決於用戶如何打算與它進行交互。
1)如果用戶將被添加和從對象的集合中刪除項目,那麼一個簡單的只得到收集屬性是最好的(選擇#1從原來的問題):
private readonly Collection<T> myCollection_ = new ...;
public Collection<T> MyCollection {
get { return this.myCollection_; }
}
這一戰略用於WindowsForms和WPF ItemsControl
控件上的Items
集合,其中用戶添加和刪除他們希望控件顯示的項目。這些控件發佈實際的集合並使用回調或事件偵聽器來跟蹤項目。
WPF還公開了一些可設置的集合,以允許用戶顯示它們控制的項目的集合,例如ItemsControl
(原始問題中的選項#3)上的ItemsSource
屬性。但是,這不是一個常見的用例。
2)如果用戶將只讀取由對象維護的數據,那麼你可以使用一個只讀集合,爲Quibblesome建議:
private readonly List<T> myPrivateCollection_ = new ...;
private ReadOnlyCollection<T> myPrivateCollectionView_;
public ReadOnlyCollection<T> MyCollection {
get {
if(this.myPrivateCollectionView_ == null) { /* lazily initialize view */ }
return this.myPrivateCollectionView_;
}
}
注意ReadOnlyCollection<T>
提供了一個實時取景基礎集合,所以你只需要創建一次視圖。
如果內部收集未實現IList<T>
,或者如果你想限制訪問更高級的用戶,可以改爲通過枚舉包裝集合訪問:
public IEnumerable<T> MyCollection {
get {
foreach(T item in this.myPrivateCollection_)
yield return item;
}
}
這種方法實現起來很簡單並且還提供了訪問所有成員而不暴露內部收藏。但是,它確實要求集合保持未修改狀態,因爲如果嘗試在修改集合後枚舉集合,則BCL集合類將引發異常。如果底層集合可能發生變化,您可以創建一個輕型包裝器來安全地枚舉集合,或返回集合的副本。
3)最後,如果你需要公開的陣列,而不是更高級別的集合,那麼你應該返回數組,以防止用戶從原單的問題修改它(選擇#2副本):
private T[] myArray_;
public T[] GetMyArray() {
T[] copy = new T[this.myArray_.Length];
this.myArray_.CopyTo(copy, 0);
return copy;
// Note: if you are using LINQ, calling the 'ToArray()'
// extension method will create a copy for you.
}
你不應該通過屬性暴露底下陣列,因爲你將不能夠告訴當用戶修改它。爲了讓修改數組,你可以添加相應的SetMyArray(T[] array)
方法,或者使用自定義索引:
public T this[int index] {
get { return this.myArray_[index]; }
set {
// TODO: validate new value; raise change event; etc.
this.myArray_[index] = value;
}
}
(當然,通過實現自定義索引,你會複製BCL類的工作:)
這會在每次讀取Collection屬性時創建新的ReadOnlycollection,這可能非常耗費資源 – Ivan 2009-09-04 16:00:54
Aye,Emperor XLII改進了他發佈的上述示例中的前提。 – Quibblesome 2009-09-11 14:25:49