到目前为止,其他答案中有很多令人困惑的地方。 (虽然 Preston Guillot 的回答相当不错,但它实际上并没有说明这里发生了什么。)让我尝试澄清一下。
First关闭,你只是运气不好。 C# 要求 foreach 语句中使用的集合:
- 实施公开
GetEnumerator
与所需的模式相匹配。
- 实施
IEnumerable
(而且当然,IEnumerable<T>
需要IEnumerable
)
- 保持动态,在这种情况下,我们只需将罐子扔到一边并在运行时进行分析即可。
结果是集合类型必须实际执行 the GetEnumerator
以一种方式或另一种方式。提供扩展方法并不能解决问题。
这是不幸的。在我看来,当 C# 团队向 C# 3 添加扩展方法时,他们应该修改现有功能,例如foreach
(甚至可能using
!)考虑扩展方法。然而,在 C# 3 发布周期中,日程安排非常紧张,任何未按时实现 LINQ 的额外工作项目都可能被削减。我不记得设计团队在这一点上说了什么,我也没有我的笔记了。
这种不幸的情况是语言不断发展和演变的结果。旧版本是为了满足时代的需要而设计的,新版本必须建立在这个基础上。与事实相反,如果 C# 1.0 有扩展方法和泛型,那么foreach
循环可以像 LINQ 一样设计:作为一个简单的语法转换。但事实并非如此,现在我们被前通用、前扩展方法设计的遗留问题所困扰。
Second,其他答案和评论中似乎存在一些关于确切需要做什么的错误信息foreach
工作。您无需实施IEnumerable
。有关此常见误解功能的更多详细信息,请参阅我关于这个主题的文章 http://blogs.msdn.com/b/ericlippert/archive/2011/06/30/following-the-pattern.aspx.
Third,似乎存在一些关于这种行为是否确实符合规范的问题。这是。不幸的是,规范没有明确指出在这种情况下不考虑扩展方法。然而,规范对于发生的情况非常清楚:
编译器首先执行会员查询 for GetEnumerator
。成员查找算法详细记录在第 7.3 节中,并且成员查找不考虑扩展方法, only 实际成员。只考虑扩展方法常规重载解析失败后,而且我们还没有达到重载分辨率。 (是的,扩展方法被认为是会员访问, but 会员访问 and 会员查询是不同的操作。)
如果成员查找未能找到方法组那么匹配模式的尝试就会失败。因此,编译器永远不会继续执行算法的重载解析部分,因此永远没有机会考虑扩展方法。
因此,您描述的行为与指定的行为一致。
我建议您阅读规范的第 8.8.4 节很小心如果您想准确了解编译器如何分析foreach
陈述。
Fourth,我鼓励您花时间以其他方式为您的程序增加价值。引人注目的好处
foreach (var row in table)
over
foreach(var row in table.Rows)
对于开发人员来说很小,而对于客户来说却是看不见的。花时间添加新功能或修复错误或分析性能,而不是将已经非常清晰的代码缩短五个字符。