61

.NET 4.5 / C# 5 では、次のプロパティIReadOnlyCollection<T>で宣言されています。Count

public interface IReadOnlyCollection<out T> : IEnumerable<T>, IEnumerable
{
    int Count { get; }
}

インターフェイスもICollection<T>実装するのは理にかなっていないのではないかと思っています。IReadOnlyCollection<T>

public interface ICollection<T> : IEnumerable<T>, IEnumerable, *IReadOnlyCollection<T>*

これは、実装ICollection<T>するクラスが自動的に実装したことを意味しますIReadOnlyCollection<T>。これは私には理にかなっているように思えます。

抽象化は、抽象化ICollection<T>の拡張と見なすことができますIReadOnlyCollection<T>List<T>たとえば、 は と の両方ICollection<T>を実装していることに注意してくださいIReadOnlyCollection<T>

ただし、そのように設計されていません。

ここで何が欠けていますか?代わりに現在の実装が選択されたのはなぜですか?


アップデート

オブジェクト指向設計の推論を使用して理由を説明する答えを探しています。

  • と の両方をList<T>実装するなどの具象クラスIReadOnlyCollection<T> ICollection<T>

以下よりも優れた設計です。

  • ICollection<T>IReadOnlyCollection<T>直接実装する

また、これは本質的に次の質問と同じであることに注意してください。

  1. なぜIList<T>実装しないのIReadOnlyList<T>ですか?
  2. なぜIDictionary<T>実装しないのIReadOnlyDictionary<T>ですか?
4

6 に答える 6

42

おそらくいくつかの理由があります。ここにあるいくつかの:

  • 大きな後方互換性の問題

    の定義をどのように書きますICollection<T>か? これは自然に見えます:

    interface ICollection<T> : IReadOnlyCollection<T>
    {
        int Count { get; }
    }
    

    ただしIReadOnlyCollection<T>、プロパティも宣言しているため、問題がありCountます (コンパイラはここで警告を発行します)。警告とは別に、それをそのままにしておく (これは を書くことと同じです) と、実装者は少なくとも 1 つを明示的に実装することで、2 つのプロパティに対して異なるnew int Count実装を持つことができます。2 つの実装が異なる値を返すことにした場合、これは「おもしろい」かもしれません。人々が自分の足で自分自身を撃つことを許可することは、C# のスタイルではありません。Count

    では、次はどうでしょうか。

    interface ICollection<T> : IReadOnlyCollection<T>
    {
        // Count is "inherited" from IReadOnlyCollection<T>
    }
    

    Countまあ、これは明示的に実装することを決定したすべての既存のコードを壊します:

    class UnluckyClass : ICollection<Foo>
    {
         int ICollection<Foo>.Count { ... } // compiler error!
    }
    

    したがって、この問題に対する良い解決策はないように思えます。既存のコードを壊すか、エラーが発生しやすい実装を全員に強制するかのどちらかです。したがって、唯一の必勝法はプレイしないことです。

于 2012-09-27T13:40:17.677 に答える
17

ジョンはここhttps://stackoverflow.com/a/12622784/395144にいました、あなたは彼の返事を答えとしてマークするべきです:

int ICollection<Foo>.Count { ... } // compiler error!

インターフェイスには明示的な実装を含めることができるため、基本インターフェイスの抽出には下位互換性がありません(基本クラスではこの問題は発生しません)。

それが理由です...

Collection<T> : IReadOnlyCollection<T>
List<T> : IReadOnlyList<T>
Dictionary<TKey, TValue> : IReadOnlyDictionary<TKey, TValue>

...しかしそれらのインターフェースではありません。

私見ですが、彼らは最初は設計エラーを起こしましたが、今では(物事を壊すことなく)完全に解決できません。

編集:非表示は役に立ちません、古い(明示的な)実装はまだビルドされません(コードを変更せずに):

interface INew<out T> { T Get(); }

interface IOld<T> : INew<T>
{
    void Set(T value);
    new T Get();
}

class Old<T> : IOld<T>
{
    T IOld<T>.Get() { return default(T); }
    void IOld<T>.Set(T value) { }
}

「Sample.Old」はインターフェースメンバー「Sample.INew.Get()」を実装していません

于 2013-02-18T20:04:42.147 に答える
0

明らかに、すべてが読み取り専用であるとは限らないため、意味的に間違っています。ICollection

そうは言っても、実装IReadableCollectionを呼び出すことができる一方で、インターフェースを呼び出すこともできます。ReadOnlyCollection

しかし、彼らはその道を進みませんでした。なんで?BCLチームのメンバーが、コレクションAPIが複雑になりすぎないようにしたいと書いているのを見ました。(すでにそうですが、率直に言って。)

于 2012-09-27T13:43:35.790 に答える
-3

あなたの質問を最初に読んだとき、「彼の言う通りだ!それが最も理にかなっているだろう」と思いました。しかし、インターフェイスのポイントは、コントラクト (動作の記述) を記述することです。クラスが を実装している場合は、読み取り専用にする必要がありIReadOnlyCollectionますCollection<T>そうではありません。したがって、Collection<T>読み取り専用を意味するインターフェイスを実装すると、かなり厄介な問題が発生する可能性があります。の消費者は、IReadOnlyCollectionその基礎となるコレクションについて特定の仮定を立てようとしています-誰もそれを変更できないため、それを反復することは安全です.

于 2012-09-27T13:32:31.443 に答える
-3

オブジェクト指向設計の推論は、クラスとそのクラスが実装するインターフェイスとの間の「Is A」関係に由来します。

.NET 4.5/c# 5.0では、とList<T>の両方です。コレクションをどのように使用するかに応じて、いずれかのタイプとしてインスタンス化できます。ICollection<T>IReadOnlyCollection<T>List<T>

ICollection<T>実装IReadOnlyCollection<T>することで、 または のいずれかになることができますList<T>が、そうすると、そうではない「Aである」ということになります。ICollection<T>IReadOnlyCollection<T>ICollection<T> IReadOnlyCollection<T>

更新しました

から継承されたすべてのクラスが実装されている場合ICollection<T>、インターフェイスIReadOnlyCollection<T>を実装する方が理にかなっていると言いICollection<T>ます。ICollection<T>そうではないので、を実装するとどうなるかを考えてみてくださいIReadOnlyCollection<T>:

public interface IReadOnlyCollection<T> : IEnumerable<T>, IEnumerable{}
public interface ICollection<T> : IReadOnlyCollection<T> {}

の署名を見ると、IS-A読み取り専用コレクションのICollection<T>ように見えます。ちょっと待って、IReadOnlyCollection を見てみましょう。ああ...実装されているので、必ずしも読み取り専用のコレクションである必要はありません。機能的には、元の質問で提案された実装は同じですが、意味的には、インターフェイスの実装を可能な限り高くプッシュする方が正しいと思います。IEnumerable<T>IEnumerable

于 2012-10-10T22:26:36.837 に答える
-4

このインターフェイスは、実際に機能するものというよりも、説明インターフェイスです。

推奨されるアプローチでは、すべてのコレクションは、広告を読むことしかできないものとして理解する必要があり、常に同じです。そのため、作成後に物を追加または削除することはできませんでした。

インターフェイスが呼び出される理由を自問することができIReadOnlyCollectionますIEnumerable<T>, IEnumerable。答えは簡単です。Enumerable は既に「読み取り専用」であるため、このタイプのインターフェイスには意味がありません。

それでは、doc IReadOnlyCollection(T)を見てみましょう

説明の最初の (そして最後の) senetecce は次のように述べています。

厳密に型指定された読み取り専用の要素のコレクションを表します。

そして、ストロングタイピングの目的を知っていれば、これですべて説明できると思います。

于 2012-09-27T13:59:22.163 に答える