为什么泛型IList <>不继承非泛型IList

Naf*_*rar 14 .net c# generics library-design

IList<T>不继承IList那里IEnumerable<out T>继承IEnumerable.

如果out修正是唯一的原因,那么为什么大多数的实施IList<T>(例如Collection<T>,List<T>)实现IList接口.

所以任何人都可以说好,如果那些陈述对于所有的实现都是真的,IList<T>那么IList在必要时直接将其强制转换.但问题是虽然IList<T>没有继承IList所以不能保证每个IList<T>对象都是IList.

此外,使用IList<object>显然不是解决方案,因为没有out修饰符泛型不能分配给较少的继承类; 并且创建List的新实例在这里不是解决方案,因为有人可能想要实际引用IList<T>作为IList指针; 并且使用List<T>insteed IList<T>实际上是一种糟糕的编程习惯,并不能用于所有目的.

如果.NET希望提供灵活性,每个实现IList<T>都不应该有非泛型实现的合同(即IList)那么为什么他们没有保留另一个实现泛型和非泛型版本的接口,并没有暗示所有具体的想要签订通用和非遗传项目的类应通过该接口签订合同.

发生铸造同样的问题ICollection<T>,以ICollectionIDictionary<TKey, TValue>IDictionary.

Dan*_*ker 7

如你所知,Tin IList<T>不是协变的.根据经验:任何可以修改其状态的类都不能协变.原因是这些类通常具有T作为其参数之一的类型的方法,例如void Add(T element).输入位置不允许使用协变类型参数.

除其他原因外,还增加了仿制药,以提供类型安全性.例如,您无法添加Elephant到列表中Apple.如果ICollection<T>要扩展ICollection,那么你可以在((ICollection)myApples).Add(someElephant)没有编译时错误的情况下调用,就像ICollection一个方法一样void Add(object obj),它似乎允许你将任何对象添加到列表中,而在实践中你只能添加对象T.因此,ICollection<T>不延长ICollectionIList<T>不延长IList.

C#的创造者之一Anders Hejlsberg 解释如下:

理想的情况是所有的泛型集合接口(例如ICollection<T>,IList<T>)将他们的非通用同行继承,使得通用接口实例可以与通用和非通用代码均可使用.

事实证明,唯一可能的通用接口是IEnumerable<T>,因为只有IEnumerable<T>反变量[sic 1 ]:In IEnumerable<T>,类型参数T仅用于"输出"位置(返回值)而不用于"输入"职位(参数).ICollection<T>并且在输入和输出位置都IList<T>使用T,因此这些接口是不变的.

1)IEnumerable<T>变的


由于.NET 4.5还有的IReadOnlyCollection<out T>IReadOnlyList<out T>协接口.但是IList<T>,ICollection<T>许多列表和集合类都没有实现或扩展它们.坦率地说,我觉得它们不是很有用,因为它们只是定义Countthis[int index].


如果我可以从头开始重新设计.Net 4.5,我会将列表接口拆分为只读协变接口IList<out T>,其中包含ContainsIndexOf可变的不变接口IMutableList<T>.然后,你可以投IList<Apple>IList<object>.我在这里实现了这个:

M42集合 - 协变集合,列表和数组.

  • 您的答案是正确的,但第一个链接/引用的描述奇怪地不正确。具体来说,IEnumerable 是 *Covariant*,而不是 *Contra-variant*。请参阅 [此答案](/sf/answers/225502791/) 以供参考。我建议把它叫出来以避免更多的混乱。 (2认同)