为什么 foreach 找不到我的 GetEnumerator 扩展方法?

2024-04-25

我正在努力使一些代码更具可读性。例如foreach(var row in table) {...}而不是foreach(DataRow row in table.Rows) {...}.

为此,我创建了一个扩展方法:

namespace System.Data {
    public static class MyExtensions {
        public static IEnumerable<DataRow> GetEnumerator( this DataTable tbl ) {
            foreach ( DataRow r in tbl.Rows ) yield return r;
        }
    }
}

但编译器仍然抛出foreach statement cannot operate on variables of type 'System.Data.DataTable' because 'System.Data.DataTable' does not contain a public definition for 'GetEnumerator'.

为了确认我正确地实现了扩展方法,我尝试了以下代码,编译器没有出现任何问题。

for ( IEnumerator<DataRow> enm = data.GetEnumerator(); enm.MoveNext(); ) {
    var row = enm.Current;
    ...
}

在你说这是因为之前IEnumerator or IEnumerator<DataRow>未实现,请考虑以下内容确实可以编译:

public class test {
    public void testMethod() {
        foreach ( var i in new MyList( 1, 'a', this ) ) { }
    }
}
public class MyList {
    private object[] _list;
    public MyList( params object[] list ) { _list = list; }
    public IEnumerator<object> GetEnumerator() { foreach ( var o in _list ) yield return o; }
}

到目前为止,其他答案中有很多令人困惑的地方。 (虽然 Preston Guillot 的回答相当不错,但它实际上并没有说明这里发生了什么。)让我尝试澄清一下。

First关闭,你只是运气不好。 C# 要求 foreach 语句中使用的集合:

  1. 实施公开GetEnumerator与所需的模式相匹配。
  2. 实施IEnumerable(而且当然,IEnumerable<T>需要IEnumerable)
  3. 保持动态,在这种情况下,我们只需将罐子扔到一边并在运行时进行分析即可。

结果是集合类型必须实际执行 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)

对于开发人员来说很小,而对于客户来说却是看不见的。花时间添加新功能或修复错误或分析性能,而不是将已经非常清晰的代码缩短五个字符。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 foreach 找不到我的 GetEnumerator 扩展方法? 的相关文章

  • ServiceStack 验证并不总是触发

    因此 我尝试使用 RavenDB 和 ServiceStack 构建端到端集成测试套件 但遇到了一个非常奇怪的问题 即验证无法对某些请求运行 这真的很奇怪 我不确定我做错了什么 我正在使用 NCrunch 有时测试通过 有时失败 希望这是一
  • C# 中的通用 foreach 循环

    给出以下代码的编译器告诉我 使用未分配的局部变量 x 有什么想法吗 public delegate Y Function
  • LogicalOperationStack 与 .Net 4.5 中的异步不兼容吗

    Trace CorrelationManager LogicalOperationStack允许具有嵌套逻辑操作标识符 其中最常见的情况是日志记录 NDC 它是否仍然可以使用async await 这是一个简单的例子 使用LogicalFl
  • 知识树中的段错误

    我正在用 c 实现一个可以从文件中读取的知识树 我的 newStr 函数出现段错误 我无法用这个问题测试我的其余代码 我对 c 没有太多经验 任何帮助将不胜感激 我的 c 文件 包括 包括 include 动物 h 包括 包括 return
  • 了解左值到右值转换的示例

    我很难理解这段代码 来自 C 14 草案标准的示例 转换拉瓦尔 调用未定义的行为g false 为什么constexpr使程序有效 另外 不访问 是什么意思 y n 在两次通话中g 我们正在返回n数据成员那么为什么最后一行说它不能访问它呢
  • 未初始化成员的警告在 C++11 上消失

    我编译这个简单的程序 include
  • 使用回溯(而不是 DFS)背后的直觉

    我正在解决单词搜索 https leetcode com problems word search description LeetCode com 上的问题 给定一个 2D 板和一个单词 查找该单词是否存在于网格中 该单词可以由顺序相邻单
  • 使用 SFML 绘制文本时出现段错误

    我做了一个Button应该绘制一些顶点和字符串的类RenderWindow 这是删除了不相关部分的代码 here http pastebin com 4a5RuS2y是完整的代码 namespace game class Button pu
  • 如何在cmake中添加cuda源代码的定义

    我使用的是 Visual Studio 2013 Windows 10 CMake 3 5 1 一切都可以使用标准 C 正确编译 例如 CMakeLists txt project Test add definitions D WINDOW
  • C# 字典循环增强

    我有一本包含大约 100 万个条目的字典 我不断地循环字典 public void DoAllJobs foreach KeyValuePair
  • 与智能指针的返回类型协方差

    在 C 中我们可以这样做 struct Base virtual Base Clone const virtual Base struct Derived Base virtual Derived Clone const overrides
  • 尝试从 C# 调用简单的 Python 脚本,但由于“无法获取 Python 编解码器”致命错误而失败。我怎样才能解决这个问题?

    相关的C 代码片段如下 static string CallPython string fileName Process p new Process p StartInfo new ProcessStartInfo C Python310
  • 创建新视图时如何初始化视图模型中的属性?

    我有一个应用程序 可以打开一个视图 允许您搜索数据 然而 为了进行搜索 用户必须选择他想要在什么类别下进行搜索 目前 我正在尝试弄清楚如何将所选类别从主视图模型 作为 int 传递到新搜索视图的视图模型 目前我正在尝试在主视图中使用类似的东
  • 如何保存具有多个缩进设置的XmlDocument?

    我需要保存一个XmlDocument以适当的缩进归档 Formatting Indented 但有些节点及其子节点必须排在一行 Formatting None 从那时起如何实现这一目标XmlTextWriter接受整个文档的设置 在 Ahm
  • 消息在事务处理时未到达 MSMQ

    我在本地计算机中创建了一个私有 MSMQ 我使用以下 C 代码将消息发送到队列 当我将队列更改为事务性队列时 消息未到达 MSMQ 但是 Send 方法中没有抛出异常 我需要做出什么改变才能使其发挥作用 using System using
  • 制作 C# 项目 DLL 和 EXE

    我正在开发一个项目 需要有一个可执行文件以便用户可以运行配置界面和一个可以嵌入其他项目以使用其他一些功能的 DLL 有没有办法让 Visual Studio 同时生成可执行文件和 DLL 而不是每次都手动切换 我同意 TJMonk15 的观
  • 学习 WPF 会提高我的 ASP.NET 技能吗? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我已经在 Windows 窗体领域工作了很多年 而且仍然如此 我完全不熟悉 ASP NET 技术 也不熟悉其他 Web 相关技术 我曾合作过 O
  • 图像处理编程

    我想知道是否有任何方法可以使用某种编程语言检测图像中对象的位置 例如 如果我有一个球的图像 每 100 毫秒更新一次 是否可以通过某些程序使用某些东西来获取球的坐标 看一下OpenCV http opencv willowgarage co
  • AZURE:workerrole 中的异步 Run()

    我有一个异步任务 async Task UploadFiles 我想在 azure 工作者角色的 Run 方法中调用 UploadFiles 上的 等待 但 await 仅适用于声明为异步的方法 那么我可以使 Run 方法异步 如下所示 p
  • 通过网络共享的 SQL CE

    我之前见过这个问题 但找不到关于什么是可能 不可能以及什么解决方法可能可用的明确解释 我有一个现有的 C 应用程序 它使用 SQL CE 来存储本地信息 该数据库只能由单个应用程序访问 并存储在用户的 appdata 文件夹中 某些环境将

随机推荐