[C#]List<T>もIList<T>も配列も公開しない

以前書いた、FxCop:List<T>を公開してはいけないという話について、
最近はもうちょっと自分的にしっくりくる書き方が見つかったよという成長記録。
 

前回のエントリーの論旨は、
・List<T>は拡張性がないから公開するなと言う
・でも、IList<T>やCollection<T>だと
 配列にAddとかしてもコンパイルエラーにならないよ
・結局List<T>公開するしかなくね?
というものでした。
 
しかし最近気づいたのだけど、どうもCollection<T>クラス
「別のコレクションをラップして自前のコレクション作ってね!」
という用途のためにあるらしく、
いわゆるファーストクラスコレクションを作るときに
これを継承すれば便利だよ、というものらしい。

例えば、編集可能な年齢コレクションを作るときは、↓こんな感じ。


public class AgeCollection : Collection<int> {
    
    public AgeCollection() : base(new List<int>()) {
    }
}

 
Collection<T>自体はコンストラクタでIList<T>を受け取るのだけど、
それを継承クラスで隠して、List<T>しか渡せなくしてしまう。
(↑では自分でList<T>を作って基底クラスに渡してるが、
 たぶんパラメータなしのコンストラクタでも
 内部的にはList<T>を作るのだと思う)

これで拡張性を犠牲にせず、
しかもコレクションが編集可能であることを保証できる。
年齢を格納してるよというのが型名でわかるのも良いでしょう。
 

個人的にさらにお気に入りなのは、
ReadOnlyCollection<T>を継承して、
読み取り専用のコレクションを作る方法。

public class AgeCollection : ReadOnlyCollection<int> {

    public AgeCollection(IList<int> list) : base(list) {
    }
}

 
この場合はIList<T>をそのまま受け取れば良い。
これで、配列をいちいちコピーして渡したりする必要もなくなる。
 
WPFでItemsControl系部品のソースとして使うコレクションも
ObservableCollection<T>使うのはあまり好きじゃなくて、
一覧上で直接ごりごり書き換える画面でない限り、
変更がある度に毎回大もとのリストから表示したい分を
ReadOnlyCollectionでラップして公開するってのをよくやる
(文章じゃあまり伝わらないと思うけどまあいいです)。