为啥 Enumerable 不继承自 IEnumerable<T>

Posted

技术标签:

【中文标题】为啥 Enumerable 不继承自 IEnumerable<T>【英文标题】:Why Enumerable doesn't inherits from IEnumerable<T>为什么 Enumerable 不继承自 IEnumerable<T> 【发布时间】:2011-03-01 13:35:47 【问题描述】:

我对这个问题很困惑,无法理解。在Enumerable文档中,我读到了这个:

实现 System.Collections.Generic.IEnumerable

还有一些像Select()这样的方法返回IEnumerable&lt;TSource&gt;,我们可以在使用它之后从像Where()这样的其他方法中使用它们。例如:

names.Select(name => name).Where(name => name.Length > 3 );

Enumerable 不继承自IEnumerable&lt;T&gt;IEnumerable&lt;T&gt; 也不包含Select()Where() 等...

我错了吗? 还是有什么原因?

【问题讨论】:

【参考方案1】:

Select()、Where() 等是“extension methods”。它们需要在“其他地方”定义,因为接口不能提供方法的实现。

您可以通过参数列表中的关键字“this”来识别扩展方法。例如:

public static IEnumerable<TSource> Where<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, bool> predicate
)

可以像使用 IEnumerable&lt;TSource&gt; 上的方法一样使用,带有一个参数:Func&lt;TSource, bool&gt; predicate

【讨论】:

【参考方案2】:

正确。但是这句话呢?

实现 System.Collections.Generic.IEnumerable

按照这句话,我们要在IEnumerable&lt;T&gt;接口中定义方法,通过继承在Enumerable类中实现。对吗?

为什么首选扩展方法而不是继承?

【讨论】:

请注意,您应该添加评论或编辑您的问题,而不是创建新答案来添加新信息或问题。【参考方案3】:

IEnumerable 出现在IEnumerable&lt;T&gt; 之前,这是一个 2.0+ 接口。

【讨论】:

【参考方案4】:

“为什么首选扩展方法而不是继承?”

Enumerable 是一个静态类,它为 IEnumerable 实现了 50 多种扩展方法。这使您可以在实现 IEnumerable 的类型上使用所有这些扩展方法,而无需强制程序员为每个集合类型实现所有这些方法。如果 Enumerable 是一个接口而不是一个静态类,那么每个集合类型(例如 List、Dictionary、Set 等)都会有自己的这些扩展方法的实现。

【讨论】:

【参考方案5】:

解决此问题的一种方法是使用Cast&lt;T&gt;() 方法将元素转换为相同的类型,该方法返回相同元素的IEnumerable&lt;T&gt; 版本。

DataTable dt = ...
dt.Rows.Cast<DataRow>().Where()...

RowsIEnumerable 类型,转换后它变成 IEnumerable&lt;DataRow&gt; 类型,这是 LINQ 扩展方法支持的。

【讨论】:

【参考方案6】:

我曾说过,您还阅读了 Jon Skeet 撰写的这篇文章 Iterators, iterator blocks and data pipelines 以获得更多见解

【讨论】:

这是关于扩展方法,而不是迭代器块

以上是关于为啥 Enumerable 不继承自 IEnumerable<T>的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Enumerable 不实现 IEnumerable?

为啥不推荐使用 Enumerable#each_with_object ?

为啥 Enumerable 中的方法返回 Enumerator?

为啥重复 Enumerable 到 Observable 转换块

为啥 Enumerable 在 Ruby 中没有长度属性?

为啥 Enumerable.Range 实现 IDisposable?