我试图理解IEnumerable接口如何工作,但发现很难理解这个概念,因为一些例子使用IEnumerator,GetEnumerator,Current,moveNext,Reset和一些例子演示IEnumerable与IEnumerator没有Current,moveNext,重置与嵌套内部类。
我需要一个简单的例子来理解这个概念,以及什么时候使用IEnumerator与Current,moveNext,Reset以及何时不适用。
答案 0 :(得分:3)
几乎从不适合使用Reset()
,因为该方法显然不可靠:例如,迭代器块不支持它。因此,实施该计划几乎没有必要担心。
如果你的意思是在实现它:大多数时候,最合适的事情是使用迭代器块(又名yield return
),因为这样做是手工操作很难,容易出错,通常没有什么用处。你需要有一些非常具体的东西,以保证手动实施一个普查员。
您看到的一些示例可能将迭代器块添加到语言之前的日期;在这种情况下,他们没有选择除了手工编写迭代器。
大多数时候:让编译器担心繁重的工作。 yield return
是你的朋友。注意:List<T>
之类的东西使用值类型的自定义迭代器等来最小化影响;请注意,当您foreach
超过List<T>
时,您实际上并未使用IEnumerable<T>
- 您只是使用原始GetEnumerator()
和关联的API。 foreach
可以使用 IEnumerable<T>
,但不需要。
答案 1 :(得分:0)
提供者========
这是一个我从枚举器中分离出类的例子。 MyEnumerableClass是Enumerable,所以如果有人需要枚举它,它可以检索类上的枚举器。
using System;
using System.Collections;
class MyEnumerableClass : IEnumerable
{
public IEnumerator GetEnumerator()
{
return new MyEnumerableClassEnumerator();
}
}
枚举器负责枚举类中的元素。 在这个例子中,我没有这个,我希望以这种方式更清楚。 在此示例中,类MyEnumerableClass和该类上的枚举器(MyEnumerableClassEnumerator)不相关。通常,枚举器枚举类中包含的内容,以便枚举器保持对类的引用。此外,如果类的状态发生了重大变化&#34;,则枚举器无法枚举它,因此它应该引发InvalidOperationException。通常在类中添加版本标识符(即int versionId)来实现此行为。枚举器被枚举后,它会保存versionId。如果在MoveNext调用中,枚举器看到versionId已更改,则会引发异常。 通过这种方式,您可以同时在同一个类上激活多个枚举器。 无论如何,这里是一个非常简单的枚举器示例
class MyEnumerableClassEnumerator : IEnumerator
{
int myStatusVariable = 0;
public object Current
{
get { return myStatusVariable; }
}
public bool MoveNext()
{
return ++myStatusVariable < 10;
}
public void Reset()
{
myStatusVariable = 0;
}
}
消费者======== 现在的消费者。 您可以通过语言(生成接口调用)或自己生成调用两种方式使用anumerator
这里的示例基于上面的类
MyEnumerableClass myEnumerableClass = new MyEnumerableClass();
foreach (var item in myEnumerableClass)
{
Console.WriteLine(item);
}
IEnumerator enumerator = myEnumerableClass.GetEnumerator();
while (enumerator.MoveNext())
{
Console.WriteLine(enumerator.Current);
}