如何公开集合完全取决于用户打算如何与之交互。
1)如果用户将在对象的集合中添加和删除项目,那么最好使用简单的 get-only 集合属性(来自原始问题的选项#1):
private readonly Collection<T> myCollection_ = new ...;
public Collection<T> MyCollection {
get { return this.myCollection_; }
}
此策略用于Items
WindowsForms 和 WPFItemsControl
控件上的集合,用户可以在其中添加和删除他们希望控件显示的项目。这些控件发布实际的集合并使用回调或事件侦听器来跟踪项目。
WPF 还公开了一些可设置的集合,以允许用户显示他们控制的项目的集合,例如ItemsSource
属性 on ItemsControl
(来自原始问题的选项 #3)。但是,这不是一个常见的用例。
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 类的工作:)