コレクションをどのように公開するかは、ユーザーがコレクションをどのように操作するかによって完全に異なります。
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)ユーザーがオブジェクトによって維持されるデータのみを読み取る場合は、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>
は、基になるコレクションのライブ ビューを提供するため、ビューを作成する必要があるのは 1 回だけであることに注意してください。
内部コレクションが を実装していない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 クラスの作業を複製することになります :)