为什么IEnumerable <t>从IEnumerable继承?</t>

时间:2008-10-21 12:46:33

标签: c# generics ienumerable

这可能是个老问题:为什么IEnumerable<T>会继承IEnumerable

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

而且,IList<T>不会从IList继承。

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

4 个答案:

答案 0 :(得分:49)

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仅用于输入位置,那么它们将是反对变体,但这在这里并不重要。)

     

&LT; ...剪断...&GT;

因此,为了回答您的问题,IEnumerable<T>继承自IEnumerable,因为它可以! : - )

答案 1 :(得分:16)

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

IEnumerable是一个“只读”接口 - 所以通用形式比非通用形式更具体并不重要。你不会通过实现两者来打破任何事情。 IEnumerator.Current会返回object,而IEnumerator<T>.Current会返回T - 这没关系,因为您可以合法地转换为object,但这可能意味着装箱。

将此与IList<T>IList进行比较 - 您可以在Add(object)上调用IList,而对于任何特定IList<T>,这可能无效(任何内容)实际上除了IList<object>之外。

Brad Abram关于这个问题的blogged with Anders' answer

答案 2 :(得分:3)

这是为了向后兼容。如果你调用一个期望一个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();
    }

答案 3 :(得分:2)

这样就可以使用不支持泛型的类。此外,.NET泛型不允许您执行诸如强制转换IList&lt; long&gt;之类的操作。作为IList&lt; int&gt;,因此当您需要固定的基类或接口时,非通用版本的接口非常有用。