2008-10-21 136 views
32

这可能是一个古老的问题:为什么IEnumerable<T>继承自IEnumerable为什么IEnumerable <T>从IEnumerable继承?

这是.NET的做法,但它带来了一些麻烦。每次我写一个类实现IEumerable<T>,我必须写两个GetEnumerator()函数,一个用于IEnumerable<T>,另一个用于IEnumerable

而且,IList<T>不自IList继承。

我不知道为什么IEnumerable<T>的设计在其他的方式。

回答

48

Straight from the horse's mouth(Hejlsberg):

地全部泛型集合接口(如ICollection<T>IList<T>)将从其非一般的同行继承,使得通用接口实例可以与通用和非均可使用通用代码。例如,如果能够将IList<T>传递给期望IList的代码,那将是方便的。

事实证明,唯一的通用接口针对这是可能是IEnumerable<T>,因为只有IEnumerable<T>是禁忌的变体:在IEnumerable<T>,类型参数T仅用于“输出”位置(返回值),而不是在“输入”位置(参数)。 ICollection<T>IList<T>在输入和输出位置都使用T,因此这些接口是不变的。 (顺便说一句,他们会一直禁忌变种如果T仅在输入位置使用,但没有真正的问题在这里。)

< ...喀嚓...>

所以,要回答你的问题,IEnumerable<T>继承自IEnumerable,因为它可以! :-)

+1

这很有趣......我真的很烦恼,`IList `没有继承`IList`,但只要你考虑到它的差异,它开始有意义... – 2009-11-29 01:01:04

+1

这太糟糕了微软从来没有定义IReadableByIndex和IReadableByIndex (Of T),可以由IList和IList(Of T)继承。 IReadableByIndex可以被IReadableByIndex(Of T)毫无困难地继承,只读索引集合的方差会非常好。 – supercat 2011-01-16 23:06:01

16

IEnumerable的答案是:“因为它不会影响类型安全性”。

IEnumerable是一个“只读”接口 - 所以通用形式比非通用形式更具体无关紧要。通过实施两者,你不会破坏任何东西。 IEnumerator.Current返回object,而IEnumerator<T>.Current返回T - 没关系,因为您总是可以合法地转换为object,尽管这可能意味着拳击。

比较这与IList<T>IList - 你可以调用Add(object)IList,而这很可能是针对任何特定IList<T>(比实际IList<object>其他任何东西)无效。

布拉德·艾布拉姆的blogged with Anders' answer大约过这个问题。

2

这样就可以与不支持泛型的类一起工作。此外,.NET泛型不会让你像IList < long>那样执行IList < int>,因此当需要固定的基类或接口时,非泛型接口版本可能非常有用。

+0

这个重要的一点。 IList 不能铸造到IList 。 – 2008-10-21 14:18:39

3

这是为了向后兼容。如果你打电话给.Net 1。1函数期望一个香草IEnumerable你可以在你的通用IEnumerable传递。

Luckilly通用的IEnumerator从旧式的IEnumerator

我通常实现返回一个枚举的私有方法,然后通过它的新旧和款式GetEnumerator方法继承。

private IEnumerator<string> Enumerator() { 
     // ... 
    } 

    public IEnumerator<string> GetEnumerator() { 
     return Enumerator(); 
    } 

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { 
     return Enumerator(); 
    } 
相关问题