C# 迭代器和枚举器的区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/716238/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 22:16:11  来源:igfitidea点击:

Distinction between iterator and enumerator

c#.netiteratorgeneratorenumeration

提问by GurdeepS

An interview question for a .NET 3.5 job is "What is the difference between an iterator and an enumerator"?

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

This is a core distinction to make, what with LINQ, etc.

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

Anyway, what is the difference? I can't seem to find a solid definition on the net. Make no mistake, I can find the meaning of the two terms but I get slightly different answers. What would be the best answer for an interview?

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

IMO an iterator "iterates" over a collection, and an enumerator provides the functionality to iterate, but this has to be called.

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

Also, using the yield keyword is said to save state. What exactly is this state? Is there an example of this benefit occurring?

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

采纳答案by Daniel Brückner

Iterating means repeating some steps, while enumerating means going through all values in a collection of values. So enumerating usually requires some form of iteration.

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

In that way, enumerating is a special case of iterating where the step is getting a value from a collection.

这样,枚举是迭代步骤从集合中获取值的特殊情况。

Note the "usually" – enumerating may also be performed recursively, but recursion and iteration are so closely related that I would not care about this small difference.

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

You may also enumerate values you do not explicitly store in a collection. For example, you can enumerate the natural number, primes, or whatever but you would calculate these values during the enumeration and not retrieve them from a physical collection. You understand this case as enumerating a virtual collection with its values defined by some logic.

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



I assume Reed Copsey got the point. In C# there are two major ways to enumerate something.

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

  1. Implement Enumerableand a class implementing IEnumerator
  2. Implement an iterator with the yieldstatement
  1. 实现Enumerable和一个类实现IEnumerator
  2. 使用yield语句实现迭代器

The first way is harder to implement and uses objects for enumerating. The second way is easier to implement and uses continuations.

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

回答by Kredns

Enumeration deals with objects while iteration deals with values only. Enumeration is used when we use vector hashtable etc while iteration are used in while loop for loop etc. I've never use the yield keyword so I couldn't tell you.

枚举处理对象,而迭代只处理值。当我们使用向量哈希表等时使用枚举,而在 while 循环中使用迭代等。我从未使用过 yield 关键字,所以我不能告诉你。

回答by John Ellinwood

"Iterators are a new feature in C# 2.0. An iterator is a method, get accessor or operator that enables you to support foreach iteration in a class or struct without having to implement the entire IEnumerable interface. Instead, you provide just an iterator, which simply traverses the data structures in your class. When the compiler detects your iterator, it will automatically generate the Current, MoveNext and Dispose methods of the IEnumerable or IEnumerable interface." - msdn

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

回答by Reed Copsey

In C# 2+, iteratorsare a way for the compiler to automatically generate the IEnumerable and/or IEnumerable<T> interfaces for you.

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

Without iterators, you would need to create a class implementing IEnumerator, including Current, MoveNext, and Reset. This requires a fair amount of work. Normally, you would create a private class that implemtented IEnumerator<T> for your type, then yourClass.GetEnumerator() would construct that private class, and return it.

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

Iterators are a way for the compiler to automatically generate this for you, using a simple syntax (yield). This lets you implement GetEnumerator() directly in your class, without a second class (The IEnumerator) being specified by you. The construction of that class, with all of its members, is done for you.

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

Iterators are very developer friendly - things are done in a very efficient way, with much less effort.

迭代器对开发人员非常友好——事情以非常有效的方式完成,工作量要少得多。

When you use foreach, the two will behave identically (provided you write your custom IEnumerator correctly). Iterators just make life much simpler.

当您使用 foreach 时,两者的行为将相同(前提是您正确编写了自定义 IEnumerator)。迭代器只是让生活变得更简单。

回答by Joshua

To understand iterators we first need to understand enumerators.

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

Enumerators are specialist objects which provide one with the means to move through an ordered list of items one at a time (the same kind of thing is sometimes called a ‘cursor'). The .NET framework provides two important interfaces relating to enumerators: IEnumerator and IEnumerable. Objects which implement IEnumerator are themselves enumerators; they support the following members:

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

  • the property Current, which points to a position on the list

  • the method MoveNext, which moves the Current item one along the list

  • the method Reset, which moves the Current item to its initial position (which is before the first item).

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

  • MoveNext 方法,它沿着列表移动当前项

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

On the other hand, Iterаtors implement the enumerаtor pаttern. .NET 2.0 introduced the iterаtor, which is а compiler-mаnifested enumerаtor. When the enumerаble object cаlls GetEnumerаtor, either directly or indirectly, the compiler generаtes аnd returns аn аppropriаte iterаtor object. Optionаlly, the iterаtor cаn be а combined enumerаble аnd enumerаtor object.

另一方面,迭代器实现了枚举器模式。.NET 2.0 引入了迭代器,它是编译器显示的枚举器。当可枚举对象直接或间接调用 GetEnumerator 时,编译器生成并返回一个合适的迭代器对象。可选地,迭代器可以是组合的可枚举和枚举器对象。

The essentiаl ingredient of аn iterаtor block is the yield stаtement. There is one big difference between iterаtors аnd enumerаtors: Iterаtors do not implement the Reset method. Cаlling the Reset method on аn iterаtor cаuses аn exception.

迭代器块的基本要素是 yield 语句。迭代器和枚举器之间有一个很大的区别:迭代器没有实现 Reset 方法。在迭代器上调用 Reset 方法会导致异常。

The point of iterators is to allow the easy implementation of enumerators. Where a method needs to return either an enumerator or an enumerable class for an ordered list of items, it is written so as to return each item in its correct order using the ‘yield' statement.

迭代器的重点是允许轻松实现枚举器。当一个方法需要为有序的项目列表返回一个枚举器或一个可枚举类时,它被编写为使用'yield'语句以正确的顺序返回每个项目。

回答by cdiggins

What C# calls an iteratoris more commonly (outside of the C# world) called a generatoror generator function(e.g. in Python). A generator function is a specialized case of coroutine. A C# iterator (generator) is a special form of an enumerator(a data type implementing the IEnumerableinterface).

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

I dislike this usage of the term iterator for a C# generator because it is just as much an enumerator as it is an iterator. Too late for Microsoft to change its mind though.

我不喜欢将术语迭代器用于 C# 生成器,因为它既是枚举器又是迭代器。不过,微软改变主意为时已晚。

For contrast consider that in C++ an iterator is a value which is used primarily to access sequential elements in a collection. It can be advanced, derferenced to retrieve a value, and tested to see whether the end of the collection has been reached.

相比之下,请考虑在 C++ 中,迭代器是一个值,主要用于访问集合中的顺序元素。它可以被提前、推导以检索值,并测试以查看是否已到达集合的末尾。

回答by richard

Since no examples were given, here is one that was helpful to me.

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

An enumerator is an object that you get when you call .GetEnumerator() on a class or type that implements the IEnumerator interface. When this interface is implemented, you have created all the code necessary for the compilor to enable you to use foreachto "iterate" over your collection.

枚举器是在实现 IEnumerator 接口的类或类型上调用 .GetEnumerator() 时获得的对象。实现此接口后,您已经创建了编译器所需的所有代码,使您foreach能够“迭代”您的集合。

Don't get that word 'iterate" confused with iterator though. Both the Enumerator and the iterator allow you to "iterate". Enumerating and iterating are basically the same process, but are implemented differently. Enumerating means you've impleneted the IEnumerator interface. Iterating means you've created the iterator construct in your class (demonstrated below), and you are calling foreachon your class, at which time the compilor automatically creates the enumerator functionality for you.

不要把“迭代”这个词与迭代器混淆。枚举器和迭代器都允许你“迭代”。枚举和迭代基本上是相同的过程,但实现方式不同。枚举意味着你已经实现了 IEnumerator 接口. 迭代意味着您已经在您的类中创建了迭代器构造(如下所示),并且您正在调用foreach您的类,此时编译器会自动为您创建枚举器功能。

Also note that you don't have to do squat with your enumerator. You can call MyClass.GetEnumerator()all day long, and do nothing with it (example:

另请注意,您不必对枚举器进行深蹲。你可以MyClass.GetEnumerator()整天打电话,什么也不做(例如:

IEnumerator myEnumeratorThatIWillDoNothingWith = MyClass.GetEnumerator()).

IEnumerator myEnumeratorThatIWillDoNothingWith = MyClass.GetEnumerator())。

Note too that your iterator construct in your class only realy gets used when you are actually using it, i.e. you've called foreachon your class.

还要注意,您的类中的迭代器构造只有在您实际使用它时才会真正被使用,即您已经调用foreach了您的类。

Here is an iterator example from msdn:

这是来自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

回答by Ping

"Whereas a foreach statement is the consumer of the enumerator, an iterator is the producer of the enumerator."

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

The above is how "C# 5.0 In A NutShell" explains it, and has been helpful for me.

以上是“C# 5.0 In A NutShell”的解释,对我很有帮助。

In other words, the foreach statement uses MoveNext(), and the Current property of the IEnumerator to iterate through a sequence, while the iterator is used to produce the implementation of the IEnumerator that will be used by the foreach statement. In C#, when you write an iterator method containing a yield statement, the compiler will generate a private enumerator for you. And when you iterate through the items in the sequence, it will call the MoveNext() and Current property of the private enumerator. These methods/properties are implemented by your code in the iterator method that will be called repeately to yield values until there are not values left to yield.

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

This is my understanding of how C# define enumerators, and iterators.

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