迭代器和枚举器之间的区别

时间:2009-04-04 01:09:33

标签: c# .net iterator generator enumeration

.NET 3.5作业的面试问题是“迭代器和枚举器之间有什么区别”?

这是一个核心区别,LINQ等等。

无论如何,有什么区别?我似乎无法在网上找到一个可靠的定义。毫无疑问,我可以找到两个术语的含义,但我得到的答案略有不同。什么是面试的最佳答案?

IMO迭代器“迭代”集合,枚举器提供迭代功能,但必须调用它。

此外,使用yield关键字据说可以保存状态。究竟是什么状态?是否有这种好处的例子?

9 个答案:

答案 0 :(得分:51)

迭代意味着重复一些步骤,而枚举意味着遍历值集合中的所有值。所以枚举通常需要某种形式的迭代。

通过这种方式,枚举是迭代步骤从集合中获取值的特殊情况。

注意“通常” - 枚举也可以递归执行,但递归和迭代是如此密切相关,我不关心这个小差异。

您还可以枚举未明确存储在集合中的值。例如,您可以枚举自然数,素数或其他,但您可以在枚举期间计算这些值,而不是从物理集合中检索它们。您理解这种情况是枚举虚拟集合,其值由某些逻辑定义。


我认为Reed Copsey明白了这一点。在C#中有两种主要的枚举方式。

  1. 实施Enumerable和实施IEnumerator
  2. 的班级
  3. 使用yield语句
  4. 实现迭代器

    第一种方法更难实现并使用对象进行枚举。第二种方法更容易实现并使用延续。

答案 1 :(得分:43)

在C#2 +中,iterators是编译器自动生成IEnumerable和/或IEnumerable< T>的一种方式。接口。

如果没有迭代器,您需要创建一个实现IEnumerator的类,包括Current,MoveNext和Reset。这需要相当多的工作。通常,您将创建一个实现IEnumerator< T>的私有类。对于你的类型,那么yourClass.GetEnumerator()将构造该私有类,并将其返回。

迭代器是编译器使用简单语法(yield)自动为您生成此内容的一种方法。这使您可以直接在类中实现GetEnumerator(),而无需指定第二个类(IEnumerator)。该类及其所有成员的构建都是为您完成的。

迭代器非常适合开发人员 - 事情以非常有效的方式完成,而且工作量更少。

使用foreach时,两者的行为相同(假设您正确编写了自定义IEnumerator)。迭代器只会简化生活。

答案 2 :(得分:18)

C#调用迭代器更常见的是(在C#世界之外)称为generator生成器函数(例如在Python中)。生成器函数是coroutine的特殊情况。 C#迭代器(生成器)是枚举器(实现IEnumerable接口的数据类型)的特殊形式。

我不喜欢C#生成器的术语迭代器的这种用法,因为它和枚举器一样多,也是迭代器。微软改变主意的时间太晚了。

相反,请注意,在C ++中,迭代器是一个主要用于访问集合中的顺序元素的值。它可以是高级的,用于检索值,并进行测试以查看是否已达到集合的结尾。

答案 3 :(得分:12)

要理解迭代器,我们首先需要了解枚举器。

枚举器是专家对象,它为一个人提供了一次一个地移动一个有序的项目列表的方法(同样的东西有时被称为“光标”)。 .NET框架提供了两个与枚举器相关的重要接口:IEnumerator和IEnumerable。实现IEnumerator的对象本身就是枚举器;他们支持以下成员:

  • 属性Current,指向列表中的位置

  • 方法MoveNext,它沿着列表

  • 移动当前项目1
  • 方法Reset,它将Current项目移动到其初始位置(在第一个项目之前)。

另一方面,Iterаtors实施了enumerrator。 .NET 2.0引入了iterаtor,它是一个编译器实现的枚举器。当可插入的对象直接或间接地编写GetEnumerаtor时,编译器会生成并返回一个对应的iterаtor对象。可选择地,它可以是一个组合的可用对象和对象。

iterаtor区块的重要成分是收益率。 iterаtors和enumertors之间有一个很大的区别:Iterаtors没有实现Reset方法。将it方法上的Reset方法设置为异常。

迭代器的目的是允许简单地实现枚举器。如果一个方法需要为一个有序的项目列表返回一个枚举器或一个可枚举的类,那么它的编写方式是使用'yield'语句以正确的顺序返回每个项目。

答案 4 :(得分:11)

“foreach语句是枚举器的使用者,而迭代器是枚举器的生产者。”

以上是“C#5.0在NutShell中”的解释,并对我有所帮助。

换句话说,foreach语句使用MoveNext()和IEnumerator的Current属性来迭代序列,而迭代器用于生成将由foreach语句使用的IEnumerator的实现。在C#中,当您编写包含yield语句的迭代器方法时,编译器将为您生成一个私有枚举器。当您遍历序列中的项时,它将调用私有枚举器的MoveNext()和Current属性。这些方法/属性由迭代器方法中的代码实现,该方法将被重复调用以产生值,直到没有剩余的值产生。

这是我对C#定义枚举器和迭代器的理解。

答案 5 :(得分:7)

由于没有给出任何例子,这里有一个对我有帮助的例子。

枚举器是在实现IEnumerator接口的类或类型上调用.GetEnumerator()时获得的对象。实现此接口后,您已经创建了编译器所需的所有代码,使您可以使用foreach来"迭代"在你的收藏。

没有得到这个词'迭代"虽然与迭代器混淆。 Enumerator和迭代器都允许你重复"迭代"。枚举和迭代基本上是相同的过程,但实现方式不同。枚举意味着您已经实现了IEnumerator接口。迭代意味着您已经在类中创建了迭代器构造(如下所示),并且您在类上调用foreach,此时compilor会自动为您创建枚举器功能。

另请注意,您不必与您的普查员蹲坐。你可以整天打电话给MyClass.GetEnumerator(),并且不做任何事情(例如:

IEnumerator myEnumeratorThatIWillDoNothingWith = MyClass.GetEnumerator())。

另请注意,您的类中的迭代器构造仅在实际使用时才会被使用,即您在类上调用了foreach

以下是来自msdn的迭代器示例:

public class DaysOfTheWeek : System.Collections.IEnumerable
{

     string[] days = { "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" };

     //This is the iterator!!!
     public System.Collections.IEnumerator GetEnumerator()
     {
         for (int i = 0; i < days.Length; i++)
         {
             yield return days[i];
         }
     }

}

class TestDaysOfTheWeek
{
    static void Main()
    {
        // Create an instance of the collection class
        DaysOfTheWeek week = new DaysOfTheWeek();

        // Iterate with foreach - this is using the iterator!!! When the compiler
        //detects your iterator, it will automatically generate the Current, 
        //MoveNext and Dispose methods of the IEnumerator or IEnumerator<T> interface
        foreach (string day in week)
        {
            System.Console.Write(day + " ");
        }
    }
}
// Output: Sun Mon Tue Wed Thr Fri Sat

答案 6 :(得分:3)

“迭代器是C#2.0中的一个新特性。迭代器是一个方法,get访问器或运算符,使您能够在类或结构中支持foreach迭代,而无需实现整个IEnumerable接口。相反,您只提供一个iterator,它只是遍历你的类中的数据结构。当编译器检测到你的迭代器时,它会自动生成IEnumerable或IEnumerable接口的Current,MoveNext和Dispose方法。“ - msdn

答案 7 :(得分:2)

枚举处理对象,而迭代仅处理值。当我们使用向量哈希表等时使用枚举,而迭代用于循环的while循环等。我从来没有使用yield关键字,所以我不能告诉你。

答案 8 :(得分:0)

迭代处理数组字符串,而迭代处理对象

在JavaScript中,您可以使用以下命令迭代数组或字符串:

  • forEach 循环
  • for 循环
  • for 循环
  • 做而循环
  • while 循环

您可以使用:

枚举对象
  • 用于循环
  • Object.keys()方法
  • Object.values()方法
  • Object.entries()方法