为什么IEnumerable< T>继承自IEnumerable?
-
03-07-2019 - |
题
这可能是一个老问题:为什么 IEnumerable< T>
继承自 IEnumerable
?
.NET就是这样做的,但它带来了一些麻烦。每次我编写一个类实现 IEumerable< T>
时,我必须编写两个 GetEnumerator()
函数,一个用于 IEnumerable< T>
和另一个用于 IEnumerable
。
并且, IList< T>
不会从IList继承。
我不知道为什么 IEnumerable< T>
是以其他方式设计的。
解决方案
直接离开马口(Hejlsberg) :
理想情况下,所有通用集合接口(例如
ICollection< T>
,IList< T>
)将从其非通用对应物继承,以便通用接口实例可以用于通用和非通用代码。例如,如果IList< T>
可以传递给需要IList
的代码,那将会很方便。事实证明,唯一可能的通用接口是
IEnumerable< T>
,因为只有IEnumerable< T>
是反变式的:In <代码> IEnumerable&lt; T&gt; ,类型参数T仅在“输出”中使用。位置(返回值)而不是“输入”职位(参数)。ICollection&lt; T&gt;
和IList&lt; T&gt;
在输入和输出位置都使用T,因此这些接口是不变的。 (顺便说一句,如果T仅用于输入位置,那么它们将是反对变体,但这在这里并不重要。)&LT; ...剪断...&GT;
所以,为了回答你的问题, IEnumerable&lt; T&gt;
继承自 IEnumerable
,因为它可以! : - )
其他提示
IEnumerable
的答案是:“因为它可以在不影响类型安全的情况下”。
IEnumerable
是“只读”的。接口 - 因此通用形式比非通用形式更具体并不重要。你不会通过实现两者来打破任何事情。 IEnumerator.Current
返回 object
,而 IEnumerator&lt; T&gt; .Current
返回 T
- 这没关系,你可以总是合法地转换为 object
,虽然它可能意味着拳击。
将此与 IList&lt; T&gt;
和 IList
进行比较 - 您可以在 IList
Add(object) >,对于任何特定的 IList&lt; T&gt;
(除了 IList&lt; object&gt;
之外的其他任何东西),这可能无效。
Brad Abram的以Anders的答案为博客这个问题。
这是为了向后兼容。如果你调用一个期望一个vanilla IEnumerable的.Net 1.1函数,你可以传入你的通用IEnumerable。
Luckilly,通用IEnumerator继承自旧式IEnumerator
我通常实现一个返回枚举器的私有方法,然后为旧式和新式GetEnumerator方法传递它。
private IEnumerator<string> Enumerator() {
// ...
}
public IEnumerator<string> GetEnumerator() {
return Enumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return Enumerator();
}
这样就可以使用不支持泛型的类。此外,.NET泛型不允许您执行诸如强制转换IList&lt; long&gt;之类的操作。作为IList&lt; int&gt;,因此当您需要固定的基类或接口时,非通用版本的接口非常有用。