如何公开集合完全取决于用户打算如何与其交互。
1)如果用户要从对象的集合中添加和删除项目,那么一个简单的仅获取集合属性是最好的(原始问题中的选项#1):
private readonly Collection<T> myCollection_ = new ...;
public Collection<T> MyCollection {
get { return this.myCollection_; }
}
该策略用于Items
WindowsForms 和 WPF 上的集合ItemsControl
控件,用户可以在其中添加和删除他们希望控件显示的项目。这些控件发布实际的集合并使用回调或事件侦听器来跟踪项目。
WPF 还公开了一些可设置的集合,以允许用户显示他们控制的项目的集合,例如ItemsSource
属性于ItemsControl
(原始问题中的选项#3)。然而,这不是常见的用例。
2)如果用户只读取对象维护的数据,那么您可以使用只读集合,如下所示狡辩 https://stackoverflow.com/questions/35007/how-to-expose-a-collection-property#35065建议:
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 类的工作:)