C# IEnumerable、IEnumerator 重置函数未被调用

标签 c# foreach enumerable enumerator

我基本上是在尝试让我的类能够使用 foreach 进行迭代。我读了这个教程。 MSDN .看起来很直接。但是,当我想第二次迭代时,我遇到了问题。我调试了它;事实证明它没有调用 Reset() 函数。

A类

class A : IEnumerable, IEnumerator
{
    int[] data = { 0, 1, 2, 3, 4 };

    int position = -1;

    public object Current
    {
        get
        {
            return data[position];
        }
    }

    public bool MoveNext()
    {
        position++;
        return (position < data.Length);
    }

    public void Reset()
    {
        position = -1;
    }

    public IEnumerator GetEnumerator()
    {
        return (IEnumerator)this;
    }
}

当我运行以下主要功能时;它从不调用 Reset() 函数。因此,在一个循环之后,我再也无法迭代我的类了。

主要内容

static void Main(string[] args)
{
    A a = new A();

    foreach (var item in a)
    {
        Console.WriteLine(item);
    }

    Console.WriteLine("--- First foreach finished. ---");

    foreach (var item in a)
    {
        Console.WriteLine(item);
    }
}

输出:

0
1
2
3
4
--- First foreach finished. ---
Press any key to continue . . .

有什么想法吗?

最佳答案

每次foreach被调用,它要求一个新的 IEnumerator .返回你的类实例是个坏主意 - 你应该创建一个单独的类来实现 IEnumerator ,并返回它。

这通常是通过使用嵌套(私有(private))类并返回它的一个实例来完成的。您可以将 A 类实例传递给私有(private)类(使其可以访问 data ),然后将 position该类中的字段。它将允许同时创建多个枚举器,并将与后续的 foreach 调用一起正常工作。

例如,要修改您的代码,您需要执行以下操作:

using System;
using System.Collections;

class A : IEnumerable
{
    int[] data = { 0, 1, 2, 3, 4 };

    public IEnumerator GetEnumerator()
    {
        return new AEnumerator(this);
    }

    private class AEnumerator : IEnumerator
    {
        public AEnumerator(A inst)
        {
            this.instance = inst;
        }

        private A instance;
        private int position = -1;

        public object Current
        {
            get
            {
                return instance.data[position];
            }
        }

        public bool MoveNext()
        {
            position++;
            return (position < instance.data.Length);
        }

        public void Reset()
        {
            position = -1;
        }

    }
}

请注意,您也可以直接返回数组的枚举器(尽管我假设您正在尝试学习如何制作干净的枚举器):

class A : IEnumerable
{
    int[] data = { 0, 1, 2, 3, 4 };

    public IEnumerator GetEnumerator()
    {
        return data.GetEnumerator();
    }
}

最后,你可以使用iterators以更简单的方式实现这一点:

class A : IEnumerable
{
    int[] data = { 0, 1, 2, 3, 4 };

    public IEnumerator GetEnumerator()
    {
        for (int i=0;i<data.Length;++i)
           yield return data[i];
    }
}

话虽如此,我强烈建议实现 IEnumerable<int>除了IEnumerable。泛型使这在使用方面变得更好。

关于C# IEnumerable、IEnumerator 重置函数未被调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11475328/

相关文章:

ruby - 如何在一行内遍历这个散列?

c# - C# 中的快速傅立叶变换

c# - 如何将 C++ GDI 代码放入 C# 项目中

php - 我的脚本在 foreach 循环后停止

java - Velocity #foreach 无法按预期工作,字符串作为 $value 变量传递

c# - 如何使 DataTable 可枚举?

ruby-on-rails - 如何按此哈希数组分组(可枚举)[Ruby、Rails]

c# - Windows 身份验证模拟 - 第二个请求获得错误的用户身份

c# - 使用 Bootstrap 从 HTML 转换为 .NET MVC

php - 打印超出数组第一行的内容