.NET 3.5作业的面试问题是“迭代器和枚举器有什么区别”?
这是要做出的核心区分,对于LINQ等等。
无论如何,有什么区别?我似乎在网上找不到可靠的定义。没错,我可以找到两个术语的含义,但是得到的答案略有不同。面试的最佳答案是什么?
IMO迭代器在集合上“迭代”,并且枚举器提供了迭代功能,但这必须调用。
另外,据说使用yield关键字可以保存状态。这个状态到底是什么?有这种好处发生的例子吗?
Answers:
迭代意味着重复一些步骤,而枚举意味着遍历值集合中的所有值。因此,枚举通常需要某种形式的迭代。
这样,枚举是迭代步骤的特殊情况,步骤是从集合中获取值。
注意“通常” –枚举也可以递归执行,但是递归和迭代是如此紧密相关,以至于我不会在意这个小的差异。
您还可以枚举没有显式存储在集合中的值。例如,您可以枚举自然数,素数或其他任何东西,但是您将在枚举期间计算这些值,而不从物理集合中检索它们。您将这种情况理解为枚举虚拟集合,其值由某些逻辑定义。
我认为里德·科普西(Reed Copsey)明白了这一点。在C#中,有两种主要的枚举方法。
Enumerable
和类实施IEnumerator
yield
语句实现迭代器第一种方法更难实现,并使用对象进行枚举。第二种方法更易于实现并使用延续。
在C#2+中,迭代器是编译器自动为您生成IEnumerable和/或IEnumerable <T>接口的一种方式。
如果没有迭代器,则需要创建一个实现IEnumerator的类,包括Current,MoveNext和Reset。这需要大量的工作。通常,您将创建一个私有类,该私有类会为您的类型隐含IEnumerator <T>,然后yourClass.GetEnumerator()将构造该私有类并返回它。
迭代器是编译器使用一种简单的语法(收益)自动为您生成此代码的方法。这使您可以直接在您的类中实现GetEnumerator(),而无需您指定第二个类(IEnumerator)。该类及其所有成员的构造已为您完成。
迭代器对开发人员非常友好-事情以非常有效的方式完成,而工作量却少得多。
使用foreach时,两者的行为将相同(前提是您正确编写了自定义IEnumerator)。迭代器使生活变得简单得多。
“虽然foreach语句是枚举器的使用者,但迭代器是枚举器的使用者。”
以上是“ C#5.0在一个NutShell中”的解释方式,对我有所帮助。
换句话说,foreach语句使用MoveNext()和IEnumerator的Current属性来遍历序列,而迭代器用于生成将被foreach语句使用的IEnumerator的实现。在C#中,当您编写包含yield语句的迭代器方法时,编译器将为您生成一个私有枚举器。当您遍历序列中的项目时,它将调用私有枚举器的MoveNext()和Current属性。这些方法/属性由您在迭代器方法中的代码实现,将被重复调用以产生值,直到没有剩余值可产生为止。
这是我对C#如何定义枚举数和迭代器的理解。
要了解迭代器,我们首先需要了解枚举器。
枚举器是一种特殊的对象,它使人们能够一次浏览一件物品的有序列表(同一类物品有时称为“光标”)。.NET框架提供了两个与枚举器有关的重要接口:IEnumerator和IEnumerable。实现IEnumerator的对象本身就是枚举器;他们支持以下成员:
属性Current,它指向列表中的位置
MoveNext方法,该方法将当前项沿列表移动一
Reset方法,将Current项目移动到其初始位置(在第一个项目之前)。
另一方面,迭代器实现枚举器模式。.NET 2.0引入了迭代器,该迭代器是编译器枚举的枚举器。当可枚举对象直接或间接调用GetEnumertor时,编译器将生成并返回一个适当的迭代器对象。可选地,迭代器可以是枚举对象和枚举对象的组合。
迭代器块的重要组成部分是产量策略。迭代器和枚举器之间有一个很大的区别:迭代器不实现Reset方法。在迭代器上调用Reset方法会导致异常。
迭代器的目的是允许轻松实现枚举器。如果方法需要为项目的有序列表返回枚举器或可枚举的类,则将其编写为使用“ yield”语句按正确的顺序返回每个项目。
由于没有给出示例,因此这对我很有帮助。
枚举数是在实现IEnumerator接口的类或类型上调用.GetEnumerator()时获得的对象。实施此接口后,您已经创建了编译器所需的所有代码,以使您foreach
能够“迭代”整个集合。
不过不要把“ iterate”一词与迭代器混淆了,Enumerator和Iterator都允许您“迭代”。枚举和迭代基本上是相同的过程,但是实现方式不同。枚举意味着您已经实现了IEnumerator接口。迭代意味着您已经在类中创建了迭代器构造(如下所示),并且您正在调用foreach
类,这时编译器会自动为您创建枚举器功能。
还要注意,您不必蹲下枚举器。您可以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
枚举处理对象,而迭代仅处理值。当我们使用向量哈希表等时使用枚举,而在while循环中使用迭代时使用枚举。我从未使用过yield关键字,所以我无法告诉您。
迭代处理数组和字符串,而迭代处理对象
在JavaScript中,您可以使用以下方法迭代数组或字符串:
您可以使用以下方法枚举对象: