无法理解IEnumerator

时间:2011-11-02 15:34:16

标签: c# .net ienumerable

我目前正在学习C#,目的是有效地使用Razor和Umbraco,我有一些PHP背景和JavaScript的合理知识。

我遇到了IEnumerator界面,很难理解它。我在下面设置了一个代码片段来演示使用foreach循环遍历数组:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace cardEnum
{
    class suitsEnumerator
    {
        private static string[] suits = { "Hearts", "Spades", "Diamonds", "Clubs" };
        public void showAll()
        {
            foreach(string x in suits){
                System.Console.WriteLine(x);
            }
        }
    }
    class run
    {
        static void Main()
        {
            Console.WriteLine("The suits are:");
            var suits = new suitsEnumerator();
            suits.showAll();
            Console.ReadKey();
        }
    }
}

有人可以解释为什么我甚至需要使用IEnumerator,否则我很容易在数组中循环。我知道这是一个如此简单的问题,我只是想不出使用IEnumerable的原因。

非常感谢任何帮助,谢谢!

7 个答案:

答案 0 :(得分:2)

首先,如果要创建自己的枚举器,则应该使类实现IEnumerator接口(或其通用等价物)。

public class FooEnumerator : IEnumerator
{
    #region IEnumerator Members

    public object Current
    {
        get { throw new NotImplementedException(); }
    }

    public bool MoveNext()
    {
        throw new NotImplementedException();
    }

    public void Reset()
    {
        throw new NotImplementedException();
    }

    #endregion
}

通常,枚举器用于通过集合一次移动一个项目。它是一个简单的界面,用于支持移动项目,但不代表项目本身。它只有当前项目的概念并且会移动到下一个项目。

另一方面,IEnumerable旨在表示项目的集合。 IEnumerable,根据其定义,返回一个枚举器,其目的是枚举IEnumerable集合中的每个项目。它们不是互斥的类,是依赖类。

您通常不会像示例中那样创建一个枚举器来浏览您的值。您将创建一个集合并使用枚举器来导航它(或者在更高级别迭代使用幕后枚举器的集合)。

答案 1 :(得分:2)

这是在您的示例中实现枚举器模式的方式。我希望这澄清了一些事情,特别是IEnumerableIEnumerator之间的关系:

namespace cardEnum {
    // simple manual enumerator
    class SuitsEnumerator : IEnumerator {
        private int pos = -1;
        private static string[] suits = { "Hearts", "Spades", "Diamonds", "Clubs" };

        public object Current {
            get { return suits[pos]; }
        }

        public bool MoveNext() {
            pos++;
            return (pos < suits.Length);
        }

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

    class Suits : IEnumerable {
        public IEnumerator GetEnumerator() {
            return new SuitsEnumerator();
        }
    }

    class run {
        static void Main() {
            Console.WriteLine("The suits are:");
            var suits = new Suits();
            foreach (var suit in suits) {
                Console.WriteLine(suit);
            }
            Console.ReadKey();
        }
    }
}

当然,这是一个帮助理解的人为例子。由于string[]已经实现IEnumerable,因此没有理由重新发明轮子。


由于C#支持yields关键字,因此最近创建枚举器变得容易一些:

namespace cardEnum {
    // no explicit SuitsEnumerator required
    class Suits : IEnumerable {
        public IEnumerator GetEnumerator() {
            yield return "Hearts";
            yield return "Spades";
            yield return "Diamonds";
            yield return "Clubs";
        }
    }

    class run {
        static void Main() {
            Console.WriteLine("The suits are:");
            var suits = new Suits();
            foreach (var suit in suits) {
                Console.WriteLine(suit);
            }
            Console.ReadKey();
        }
    }
}

答案 2 :(得分:1)

C#编译器将其转换为:

foreach(string x in suits)

使用IEnumerator(或IEnumerator<T>)。

IEnumerableIEnumerable<T>接口定义了GetEnumerator方法,该方法分别返回IEnumerator(或IEnumerator<T>),该方法用于您正在使用foreach进行迭代。

异常是使用数组进行迭代,编译器对此进行不同的处理(感谢@Jon Skeet)。

答案 3 :(得分:1)

您可能(通常会)必须执行一些更复杂的操作,而不仅仅是打印出对象的值。

您的类可能必须逐个返回(yield)对象以进行某些外部处理(通过其他类,方法等)。

然后公开IEnumerator比返回整个集合更好,因为枚举意味着你当时只传递一个对象!不是一列(可能)一个百万元素。

答案 4 :(得分:1)

这很好,因为您的代码依赖于接口(IEnumerable

今天代码中的套装类型是Array

private static string[] suits = { "Hearts", "Spades", "Diamonds", "Clubs" };

如果你决定使用for循环,你的代码看起来或多或少就像下面的

for (int index = 0; index < suits.Length; suits++)
{
    // code here
}

明年,您可能有理由将其类型从Array更改为List<T>。如果您使用,则需要更新代码块,因为Array具有Length而List具有Count属性。

答案 5 :(得分:0)

如果你看一下System.Array,你会发现Array实现了IEnumerable。 而且每个都不需要IEnumerable对象。它只需要一个名为GetEnumerator的方法。

答案 6 :(得分:0)

假设您要创建一个自定义的套装集合......学习如何实现IEnumerable<T>将会让您对它为何如此有用有所了解。没有它,LINQ就不会像我们所知的那样存在。