2011 年 1 月 6 日更新:
信じられないかもしれませんが、私はこのインターフェイスを、私が始めたオープン ソース ライブラリ Tao.NET に組み込みました。このライブラリのインターフェイスを説明するブログ投稿を書きましたIArray<T>
。これは、この質問で最初に提起した問題 (1 年前?!) に対処するだけでなく、BCL に (私の意見では) 非常に欠けている共変インデックス インターフェイスも提供します。
質問(要するに):
なぜ .NET には があり、リストを変更するメソッド ( 、 など) を実装して提供するのに、リストを変更せIList<T>
ずにインデックスによるランダム アクセスを提供するなどの中間インターフェイスを提供しないのかと尋ねました。ICollection<T>
Add
Remove
IArray<T>
編集 2010-Jan-21 2:22 PM EST:
Jon Skeet の元の回答 ( のようなコントラクトが必要になる頻度について彼は質問した) へのコメントで、クラスIArray<T>
のKeys
とValues
プロパティはそれぞれとであり、Jon は次のように回答したと述べました。SortedList<TKey, TValues>
IList<TKey>
IList<Value>
ただし、この場合は IList であると宣言されており、インデクサーを使用するだけでよいことがわかります。. . . とてもエレガントというわけではありません。
これは合理的ですが、それができないことを知っているだけなので、痛みはありません. しかし、あなたが知っている理由は、コードから明らかだからではありません。SortedList<TKey, TValue>
クラスの経験があるということです。
これを行っても、Visual Studio は警告を表示しません。
SortedList<string, int> mySortedList = new SortedList<string, int>();
// ...
IList<string> keys = mySortedList.Keys;
keys.Add("newkey");
によると、それは合法IList<string>
です。しかし、例外が発生することは誰もが知っています。
ギヨームも適切な点を指摘しました。
インターフェイスは完璧ではありませんが、開発者は Add/Remove/Set を呼び出す前に IsReadOnly プロパティを確認できます...
繰り返しますが、これは理にかなっていますが、少し遠回りだと思いませんか?
次のようにインターフェイスを定義したとします。
public interface ICanWalkAndRun {
bool IsCapableOfRunning { get; }
void Walk();
void Run();
}
ここで、このインターフェイスを実装することを一般的な方法にしたとします。ただし、そのWalk
メソッドについてのみです。多くの場合、私は...に設定IsCapableOfRunning
してonfalse
をスローすることを選択します。NotSupportedException
Run
次に、次のようなコードがあるかもしれません。
var walkerRunners = new Dictionary<string, ICanWalkAndRun>();
// ...
ICanWalkAndRun walkerRunner = walkerRunners["somekey"];
if (walkerRunner.IsCapableOfRunning) {
walkerRunner.Run();
} else {
walkerRunner.Walk();
}
私は気が狂っていますか、それともこの種の と呼ばれるインターフェースの目的を無効にしていますICanWalkAndRun
か?
元の投稿
.NET では、インデックスによるランダム アクセスを提供するコレクション プロパティ (またはインデックス付きコレクションを返すメソッドなど) を持つクラスを設計しているときに、/ itemsを削除し、OOP に関して「正しいことを行い」、API を壊さずに内部実装を変更できるようにインターフェイスを提供したい場合は、IList<T>
.
標準的なアプローチは、メソッド、などIList<T>
を明示的に定義する の実装を使用することです。通常は次のようなことを行います。Add
Insert
private List<T> _items;
public IList<T> Items {
get { return _items.AsReadOnly(); }
}
でも、これがなんか嫌。別の開発者が私のクラスを使用していて、私のクラスに type のプロパティがIList<T>
あり、インターフェイスの全体的な考え方が「これらは利用可能なプロパティとメソッドです」である場合、なぜNotSupportedException
(またはどのような場合でも)をスローする必要があるのですか?彼/彼女は、インターフェイスによれば完全に合法であるべきことをしようとしていますか?
インターフェースを実装し、そのメンバーの一部を明示的に定義することは、レストランを開いてメニューにいくつかのアイテムを追加するようなものだと思います.決して利用できません。
次のように、インデックスによる非常に基本的なランダム アクセスを提供するインターフェイスのようなものがあるはずですIArray<T>
が、追加/削除はありません。
public interface IArray<T> {
int Length { get; }
T this[int index] { get; }
}
そして、その、およびメソッドをIList<T>
実装ICollection<T>
しIArray<T>
て追加することができます。IndexOf
Insert
RemoveAt
もちろん、いつでもこのインターフェイスを作成して自分で使用することもできますが、それを実装していない既存の .NET クラスのすべてには役に立ちません。IList<T>
(そして、はい、 anyを取得して を吐き出すラッパーを作成できることは知っていますIArray<T>
が、... 真剣に?)
System.Collections.Generic
のインターフェイスがこのように設計された理由について、何か洞察を持っている人はいますか? 何か不足していますか?のメンバーを明示的に定義するアプローチに関する私の問題について私が言っていることに対して、説得力のある議論はありIList<T>
ますか?
.NET のクラスとインターフェイスを設計した人よりも自分のほうがよく知っているかのように、生意気に聞こえるように言っているわけではありません。私には意味がありません。しかし、私がおそらく考慮していないことがたくさんあることを認める準備ができています.