16

2011 年 1 月 6 日更新:

信じられないかもしれませんが、私はこのインターフェイスを、私が始めたオープン ソース ライブラリ Tao.NET に組み込みました。このライブラリのインターフェイスを説明するブログ投稿を書きましたIArray<T>。これは、この質問で最初に提起した問題 (1 年前?!) に対処するだけでなく、BCL に (私の意見では) 非常に欠けている共変インデックス インターフェイスも提供します。


質問(要するに):

なぜ .NET には があり、リストを変更するメソッド ( 、 など) を実装して提供するのに、リストを変更せIList<T>ずにインデックスによるランダム アクセスを提供するなどの中間インターフェイスを提供しないのかと尋ねました。ICollection<T>AddRemoveIArray<T>


編集 2010-Jan-21 2:22 PM EST:

Jon Skeet の元の回答 ( のようなコントラクトが必要になる頻度について彼は質問した) へのコメントで、クラスIArray<T>KeysValuesプロパティはそれぞれとであり、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をスローすることを選択します。NotSupportedExceptionRun

次に、次のようなコードがあるかもしれません。

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>を明示的に定義する の実装を使用することです。通常は次のようなことを行います。AddInsert

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>て追加することができます。IndexOfInsertRemoveAt

もちろん、いつでもこのインターフェイスを作成して自分で使用することもできますが、それを実装していない既存の .NET クラスのすべてには役に立ちません。IList<T>(そして、はい、 anyを取得して を吐き出すラッパーを作成できることは知っていますIArray<T>が、... 真剣に?)

System.Collections.Genericのインターフェイスがこのように設計された理由について、何か洞察を持っている人はいますか? 何か不足していますか?のメンバーを明示的に定義するアプローチに関する私の問題について私が言っていることに対して、説得力のある議論はありIList<T>ますか?

.NET のクラスとインターフェイスを設計した人よりも自分のほうがよく知っているかのように、生意気に聞こえるように言っているわけではありません。私には意味がありません。しかし、私がおそらく考慮していないことがたくさんあることを認める準備ができています.

4

3 に答える 3

6

デザインの問題は必ずしも白黒ではありません。

片側はそれぞれの状況に対応する正確なインターフェースであり、実際にインターフェースを実装するプロセス全体が本当に苦痛になります。

もう1つは、実装者によって常に完全にサポートされているとは限らないが、多くのことを容易にする多目的インターフェースです。たとえば、類似しているが「正確なインターフェース」設計で割り当てられた同じインターフェースを取得しないインスタンスを渡すなどです。 .

そのため、BCL の設計者は 2 番目の方法を選択しました。特にコレクションと、C#4 インターフェイスの co-/contravariance 機能 (これは、IEnumerable<> を除くほとんどのコレクション インターフェイスには適用できません。反変部分と同様に)。

また、文字列やプリミティブ型などの基本クラスが ICharStream (文字列のstring場合。パターン マッチングのインスタンス以外のソースを使用できるようにするために正規表現などに使用できます) や IArithmetic などの一部のインターフェイスをサポートしていないのは残念です。一般的な数学が可能になるように、数値プリミティブ。しかし、すべてのフレームワークにはいくつかの弱点があると思います。

于 2010-01-21T15:49:07.130 に答える
2

インターフェイスは完璧ではありませんが、開発者は Add/Remove/Set を呼び出す前にIsReadOnlyプロパティを確認できます...

于 2010-01-21T15:56:40.217 に答える
0

あなたが得ることができる最も近いのは、IEnumerable< T >を返すことであり、クライアント (別名呼び出し元) は .ToArray() 自体を呼び出すことができます。

于 2010-01-21T15:38:12.510 に答える