OITA: Oika's Information Technological Activities

@oika 情報技術的活動日誌。

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

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

前回のエントリーの論旨は、
・Listは拡張性がないから公開するなと言う
・でも、IListやCollectionだと
 配列にAddとかしてもコンパイルエラーにならないよ
・結局List公開するしかなくね?
というものでした。

しかし最近気づいたのだけど、どうもCollectionクラス
「別のコレクションをラップして自前のコレクション作ってね!」
という用途のためにあるらしく、
いわゆるファーストクラスコレクションを作るときに
これを継承すれば便利だよ、というものらしい。

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

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

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

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

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

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

この場合はIListをそのまま受け取れば良い。
これで、配列をいちいちコピーして渡したりする必要もなくなる。

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