Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/319.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么foreach找不到我的GetEnumerator扩展方法?_C#_Foreach_Extension Methods - Fatal编程技术网

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

C# 为什么foreach找不到我的GetEnumerator扩展方法?,c#,foreach,extension-methods,C#,Foreach,Extension Methods,我正在努力使一些代码更具可读性。例如foreach(表中的var行){…}而不是foreach(表中的DataRow.Rows){…} 为此,我创建了一个扩展方法: namespace System.Data { public static class MyExtensions { public static IEnumerable<DataRow> GetEnumerator( this DataTable tbl ) { forea

我正在努力使一些代码更具可读性。例如
foreach(表中的var行){…}
而不是
foreach(表中的DataRow.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;
        }
    }
}

在你说这是因为<代码> IEnumerator <代码>或<代码> IEnumerator < /代码>没有实现时,请考虑下面的编译:

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; }
}
公共类测试{
公共void testMethod(){
foreach(新MyList中的vari(1,'a',this)){}
}
}
公共类MyList{
私有对象[]_列表;
公共MyList(参数对象[]列表){u list=list;}
公共IEnumerator GetEnumerator(){foreach(var o在_列表中)产生返回o;}
}

一些离题:如果你想写的更可读

foreach ( DataRow r in tbl.Rows ) yield return r;
作为

现在谈谈你的问题。。试试这个

    public static IEnumerable<T> GetEnumerator<T>(this DataTable table)
    {
        return table.Rows.Cast<T>();
    }
公共静态IEnumerable GetEnumerator(此数据表)
{
return table.Rows.Cast();
}

测试类中的GetEnumerator方法不是静态的,扩展方法是静态的。这也不会编译:

class test
{
}

static class x
{
    public static IEnumerator<object> GetEnumerator(this test t) { return null; }
}

class Program
{
    static void Main(string[] args)
    {
        foreach (var i in new test()) {  }
    }
}
类测试
{
}
静态x类
{
公共静态IEnumerator GetEnumerator(此测试t){return null;}
}
班级计划
{
静态void Main(字符串[]参数)
{
foreach(新测试()中的变量i){}
}
}
为了使foreach语法正常工作,您的类必须公开一个公共GetEnumerator实例方法

编辑:


从C#9.0开始,
GetEnumerator
您的扩展相当于:

    public static IEnumerable<TDataRow> GetEnumerator<TDataRow>( this DataTable tbl ) {
        foreach ( TDataRow r in tbl.Rows ) yield return r;
    }

中的对象集合必须实现或

如果您非常希望启用此功能,那么可以创建一个包装器类,该类实现
IEnumerable
,并具有指向您的
DataTable
。或者,您可以在新类中继承
DataTable
,并实现
IEnumerable


代码可读性通常是个人偏好。我个人认为你对foreach声明所做的更改可读性较差(但我相信有很多人同意你的观点)。

到目前为止,其他答案中存在大量混乱。(尽管普雷斯顿·吉洛特的回答很好,但实际上并没有说明这里发生了什么。)让我试着澄清一下

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

  • 实现与所需模式匹配的公共
    GetEnumerator
  • 实现
    IEnumerable
    (当然,
    IEnumerable
    需要
    IEnumerable
  • 保持动态,在这种情况下,我们只需在运行时启动can并进行分析
  • 结果是,集合类型必须以某种方式实际实现
    GetEnumerator
    。提供扩展方法并不能解决这个问题

    这是不幸的。在我看来,当C++团队向C 3增加了扩展方法时,他们应该修改现有的特性,如<代码> Frace(甚至可能使用< <代码> >代码>来考虑扩展方法。然而,在C#3发布周期中,日程安排非常紧凑,任何没有按时实现LINQ的额外工作项目都可能被削减。我记不清设计团队在这一点上说了什么,我也没有我的笔记了

    这种不幸的情况是语言生长和进化的结果;旧版本是为他们的时间需求而设计的,新版本必须建立在这个基础之上。相反,如果C#1.0有扩展方法和泛型,那么
    foreach
    循环可以像LINQ:一样设计为一个简单的语法转换。但事实并非如此,现在我们仍停留在预泛型、预扩展方法设计的遗留问题上

    第二,在其他答案和评论中似乎有一些错误信息,这些信息是关于如何使
    foreach
    工作的。您不需要实现
    IEnumerable
    。有关此经常被误解的功能的更多详细信息,请参阅

    第三,似乎存在一些问题,即这种行为是否符合规范的要求。它是。规范没有明确指出在这种情况下不考虑扩展方法,这是不幸的。但是,该规范非常清楚会发生什么:

    编译器首先对
    GetEnumerator
    执行成员查找。成员查找算法在第7.3节中详细记录,并且<强>成员查找不考虑扩展方法< /强>,只考虑<强>实际成员< /强>。只有在常规重载解析失败后才考虑扩展方法,我们还没有得到重载解析。(是的,成员访问会考虑扩展方法,但成员访问和成员查找是不同的操作。)

    如果成员查找未能找到方法组,则匹配模式的尝试将失败。因此编译器永远不会进入算法的过载解决部分,因此永远没有机会考虑扩展方法。

    因此,您描述的行为与指定的行为一致

    如果您想准确理解编译器如何分析
    foreach
    语句,我建议您仔细阅读本规范第8.8.4节

    第四点,我鼓励你花时间以其他方式为你的计划增加价值。令人信服的好处

    foreach (var row in table)
    
    结束


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

    在foreach语句中,编译器是l
        public static IEnumerable<TDataRow> GetEnumerator<TDataRow>( this DataTable tbl ) {
            foreach ( TDataRow r in tbl.Rows ) yield return r;
        }
    
        public static IEnumerable<DataRow> GetEnumerator( this DataTable tbl ) {
            foreach (DataRow r in tbl.Rows ) yield return r;
        }
    
    foreach (var row in table)
    
    foreach(var row in table.Rows)
    
    namespace System.Data {
        public static class MyExtensions {
            public static IEnumerable<DataRow> GetEnumerator( this DataTable table ) {
                foreach ( DataRow r in table.Rows ) yield return r;
            }
        }
    }
    
    foreach(DataRow row in table.GetEnumerator())
      .....
    
    using System;
    using System.Collections.Generic;
    
    public static class MyExtensions
    {
        // Note: ranges aren't intended to work like this. It's just an example.
        public static IEnumerable<int> GetEnumerator(this Range range)
        {
            // .. do validation ..
            for (var i = range.Start.Value; i <= range.End.Value; i++)
            {
                yield return i;
            }
        }
    }
    
    public class ExtensionGetEnumerator
    {
    
        public void Method()
        {
            var range = 1..2;
            foreach (var i in range.GetEnumerator())
            {
                Console.WriteLine($"Print with explicit GetEnumerator {i}");
            }
    
            // The feature is in progress, scheduled for C# 9, the below does not compile yet
    
            //foreach (var i in range)
            //{
            //    Console.WriteLine($"Print with implicit GetEnumerator {i}");
            //}
        }
    }