为什么通用ICollection在.NET 4.5中实现IReadOnlyCollection?

在.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>

然而它并没有被devise成这样。

我在这里错过了什么? 为什么会select当前的实施呢?


UPDATE

我正在寻找一个使用面向对象devise推理来解释原因的答案:

  • 实现IReadOnlyCollection<T> ICollection<T>具体类如List<T> ICollection<T>

是比以下更好的devise:

  • ICollection<T> IReadOnlyCollection<T>直接实现IReadOnlyCollection<T>

还请注意,这基本上是一样的问题:

  1. 为什么IList<T>实现IReadOnlyList<T>
  2. 为什么不IDictionary<T>实现IReadOnlyDictionary<T>

乔恩在这里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> 

…但不是他们的接口。

恕我直言,他们做了一个devise错误最初,现在相当无法解决(没有打破东西)。

编辑:隐藏不帮助,旧的(显式的)实现将不会仍然生成(不修改代码):

 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()'

可能有几个原因。 这里有两个顶部:

  1. 巨大的向后兼容性问题

    你将如何写ICollection<T>的定义? 这看起来很自然:

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

    但它有一个问题,因为IReadOnlyCollection<T>也声明了一个Count属性(编译器会在这里发出警告)。 除了这个警告之外,保持原样(相当于编写new int Count )允许实现者通过至less一个显式地实现两个Count属性的不同实现。 如果两个实现决定返回不同的值,这可能是“有趣的”。 允许人们用脚踢自己而不是C#的风格。

    好的,那么怎么样:

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

    那么,这将打破所有决定明确实现Count现有代码:

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

    因此,在我看来,这个问题没有好的解决scheme:要么破坏现有的代码,要么迫使每个人都容易出错。 所以唯一的胜利就是不玩 。

  2. 语义运行时types检查

    编写像这样的代码将是没有意义的

     if (collection is IReadOnlyCollection<Foo>) 

    (或reflection的等价物),除非IReadOnlyCollection<T>是“opt-in”:如果ICollection<T>IReadOnlyCollection<Foo>的超集,那么太阳下的每个集合类都会通过这个testing,在实践中。

这在语义上是错误的,因为显然不是每个ICollection都是只读的。

也就是说,他们可以调用接口IReadableCollection ,而一个实现可以被称为ReadOnlyCollection

但是,他们没有走这条路。 为什么? 我看到一位BCL团队成员写道,他们不希望收集API变得过于复杂 。 (坦率地说,这已经是了。)

当我第一次读到你的问题时,我想:“嘿,他是对的!那会最有意义的。” 但是界面的要点是描述一个合同 – 对行为的描述。 如果你的类实现了IReadOnlyCollection ,它应该是只读的。 Collection<T>不是。 所以对于一个Collection<T>来实现一个表示只读的接口可能会导致一些非常讨厌的问题。 IReadOnlyCollection消费者将会对这个底层集合做出某些假设 – 比如迭代它是安全的,因为没有人可以修改它等等。如果它的结构如你所说,可能不是真的!

面向对象的devise推理来源于类和类实现的任何接口之间的“是”关系。

在.NET 4.5 / c#5.0中, List<T>既是ICollection<T>又是IReadOnlyCollection<T> 。 您可以将List<T>实例化为任一types,具体取决于您希望如何使用集合。

ICollection<T>实现IReadOnlyCollection<T> ,您可以让List<T>成为ICollection<T>IReadOnlyCollection<T> ,这样做可以说ICollection<T> “是A” IReadOnlyCollection<T>它不是。

更新

如果从ICollection<T>inheritance的每个类实现了IReadOnlyCollection<T>那么我认为使ICollection<T>实现接口更有意义。 由于情况并非如此,请考虑如果ICollection<T>实现IReadOnlyCollection<T>会是什么样子:

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

如果您要查看ICollection<T>的签名,它看起来像是一个只读集合。 等等,让我们看看IReadOnlyCollection和ahh …它实现IEnumerable<T>IEnumerable所以它不一定是只读集合。 在function上,原始问题提出的实现是相同的,但从语义上讲,我认为将接口实现尽可能推高是更正确的。

这个接口更多的是一个描述接口,然后真正function的东西

在build议的方法中,每一个collections都必须被理解为你只能阅读广告的东西总是一样的。 所以你不能在创build之后添加或删除一个东西。

我们可以问自己为什么这个接口被称为IReadOnlyCollection ,而不是'IReadOnlyEnumerable',因为它使用IEnumerable<T>, IEnumerable 。 答案很简单,这种types的接口不会有任何的困难,因为Enumerable已经是“只读”了。

所以让我们看看文档IReadOnlyCollection(T)

描述中的第一个(也是最后一个)塞内加说:

表示一个强types的只读元素集合。

而且我认为这个解释了一切,如果你知道什么是强types的。