.NET 3.5作业的面试问题是"迭代器和枚举器之间有什么区别"?
这是一个核心区别,LINQ等等.
无论如何,有什么区别?我似乎无法在网上找到一个可靠的定义.毫无疑问,我可以找到两个术语的含义,但我得到的答案略有不同.面试的最佳答案是什么?
IMO迭代器"迭代"集合,枚举器提供迭代功能,但必须调用它.
此外,使用yield关键字据说可以保存状态.究竟是什么状态?是否有这种好处的例子?
迭代意味着重复一些步骤,而枚举意味着遍历值集合中的所有值.所以枚举通常需要某种形式的迭代.
这样,枚举是迭代步骤从集合中获取值的特殊情况.
注意"通常" - 枚举也可以递归执行,但递归和迭代是如此紧密相关,我不关心这个小的差异.
您还可以枚举未明确存储在集合中的值.例如,您可以枚举自然数,素数或其他,但您可以在枚举期间计算这些值,而不是从物理集合中检索它们.您将此案例理解为枚举虚拟集合,其值由某些逻辑定义.
我认为Reed Copsey明白了这一点.在C#中,有两种主要的枚举方式.
实现Enumerable
和类实现IEnumerator
使用该yield
语句实现迭代器
第一种方法更难实现并使用对象进行枚举.第二种方法更容易实现并使用continuation.
在C#2 +中,迭代器是编译器为您自动生成IEnumerable和/或IEnumerable
如果没有迭代器,您需要创建一个实现IEnumerator的类,包括Current,MoveNext和Reset.这需要相当多的工作.通常,您将创建一个为您的类型实现IEnumerator
迭代器是编译器使用简单语法(yield)自动为您生成此内容的一种方法.这使您可以直接在类中实现GetEnumerator(),而无需指定第二个类(IEnumerator).该类及其所有成员的构建都是为您完成的.
迭代器非常适合开发人员 - 事情以非常有效的方式完成,而且工作量更少.
使用foreach时,两者的行为相同(前提是您正确编写自定义IEnumerator).迭代器只会让生活更简单.
C#调用迭代器的更常见的是(在C#世界之外)称为生成器或生成器函数(例如在Python中).生成器函数是协程的专用案例.AC#theerator(generator)是枚举器的一种特殊形式(实现IEnumerable
接口的数据类型).
我不喜欢C#生成器的术语迭代器的这种用法,因为它与枚举器一样多,也是迭代器.微软改变主意的时间太晚了.
相比之下,考虑到在C++中,迭代器是一个主要用于访问集合中的顺序元素的值.它可以是高级的,用于检索值,并进行测试以查看是否已达到集合的结尾.
要理解迭代器,我们首先需要了解枚举器.
枚举器是专家对象,它为一个人提供了一次一个地移动一个有序的项目列表的方法(同样的东西有时被称为"光标")..NET框架提供了两个与枚举器相关的重要接口:IEnumerator和IEnumerable.实现IEnumerator的对象本身就是枚举器; 他们支持以下成员:
属性Current,指向列表中的某个位置
MoveNext方法,它将当前项目沿列表移动一个
方法重置,将当前项目移动到其初始位置(在第一个项目之前).
另一方面,Iterаtors实施了enumerаtor..NET 2.0引入了iterаtor,它是一个编译器实现的枚举器.当可插入的对象直接或间接地编写GetEnumerаtor时,编译器会生成并返回一个对应的iterаtor对象.可选择地,它可以是一个组合的可用对象和对象.
iterаtor块的重要成分是收益率.iterаtors和enumertors之间有一个很大的区别:Iterаtors没有实现Reset方法.在iterаtor上使用Reset方法可以解决异常问题.
迭代器的要点是允许简单地实现枚举器.如果某个方法需要为一个有序的项列表返回一个枚举器或一个可枚举的类,那么它的编写方式是使用'yield'语句以正确的顺序返回每个项目.
"虽然foreach语句是枚举器的使用者,但迭代器是枚举器的生产者."
以上是"C#5.0在NutShell中"的解释,并对我有所帮助.
换句话说,foreach语句使用MoveNext()和IEnumerator的Current属性来迭代序列,而迭代器用于生成将由foreach语句使用的IEnumerator的实现.在C#中,当您编写包含yield语句的迭代器方法时,编译器将为您生成一个私有枚举器.当您遍历序列中的项时,它将调用私有枚举器的MoveNext()和Current属性.这些方法/属性由迭代器方法中的代码实现,该方法将被重复调用以产生值,直到没有剩余的值产生.
这是我对C#定义枚举器和迭代器的理解.
由于没有给出任何例子,这里有一个对我有帮助的例子.
枚举器是在实现IEnumerator接口的类或类型上调用.GetEnumerator()时获得的对象.实现此接口后,您已创建了compilor所需的所有代码,使您可以使用foreach
"迭代"集合.
不要让'迭代'这个词与迭代器混淆.枚举器和迭代器都允许你"迭代".枚举和迭代基本上是相同的过程,但实现方式不同.枚举意味着你已经实现了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 IEnumeratorinterface foreach (string day in week) { System.Console.Write(day + " "); } } } // Output: Sun Mon Tue Wed Thr Fri Sat