1、枚举器就像是序列中的“游标”或“书签”。可以有多个“书签”,移动其中任何一个都可以枚举集合,与其他枚举器互不影响。用来遍历数据结构(表链、数组、集合类成员等)。
2、可以使用foreach 遍历枚举器。foreach 用来遍历鸭子类型.点击查看foreach详细用法
实现IEnumerator接口的类就是枚举器。
枚举器就像是序列中的“游标”或“书签”。可以有多个“书签”,移动其中任何一个都可以枚举集合,与其他枚举器互不影响。用来遍历数据结构(表链、数组、集合类成员等)。
1、对于需要递归遍历的数据结构(如二叉树),指示状态可能就会变得相当复杂。为了减少实现此模式所带来的挑战,C# 2.0引入了迭代器, 新增了 yield 上下文关键字。
2、只能顺序遍历
实现了IEnumerator接口的枚举器包含3个public类型的成员:Current、MoveNext()以及Reset()。
在 IEnumerator 嵌套类中实现,以便可以创建多个枚举器。
枚举器内部可以用数组、表链、等其他数据结构。以下案例用数组
Current:返回当前处理的元素。
MoveNext():把枚举器位置向前到集合中的下一项的方法。
int[] i = {1,1,1,2 }; var ie= i.GetEnumerator(); //错误的写法,原因是枚举器位于集合中第一个元素之前,紧跟在创建枚举器之后。 MoveNext 在读取的值之前,必须调用以将枚举数前移到集合的第一个元素 Current 。 Console.Write(ie.Current); ie.MoveNext();
Reset():把位置重置为原始状态的方法。(Reset 方法通常会抛出 NotImplementedException,因此不得进行调用。如果需要重新开始枚举,只要新建一个枚举器即可。)
这种方式不好,不能创建多个枚举实例。
using System; using System.Collections; namespace ConsoleEnum { public class cars : IEnumerator,IEnumerable { private car[] carlist; int position = -1; //Create internal array in constructor. public cars() { carlist= new car[6] { new car("Ford",1992), new car("Fiat",1988), new car("Buick",1932), new car("Ford",1932), new car("Dodge",1999), new car("Honda",1977) }; } //IEnumerator and IEnumerable require these methods. public IEnumerator GetEnumerator() { return (IEnumerator)this; } //IEnumerator public bool MoveNext() { position++; return (position < carlist.Length); } //IEnumerable public void Reset() { position = -1; } //IEnumerable public object Current { get { return carlist[position];} } } }
本文中的示例尽量简单(所以采用数组而不是其他数据解构(单项表链)),以更好地解释这些接口的使用。不过该案例也反应出一个问题。
如果多线程访问方法就会造成这个实例,由于MoveNext()是共享的。就会导致乱序。
若要使代码更可靠并确保代码使用当前最佳做法准则,请修改代码,如下所示:
IEnumerator接口
的类),以便可以创建多个枚举器。Current
异常处理 IEnumerator
。 如果集合的内容更改,将 reset
调用 方法。 因此,当前枚举器失效,您将收到 IndexOutOfRangeException
异常。 其他情况也可能导致此异常。 因此,实现 Try...Catch
块以捕获此异常并引发 InvalidOperationException
异常。using System; using System.Collections; namespace ConsoleEnum { public class cars : IEnumerable { private car[] carlist; //Create internal array in constructor. public cars() { carlist= new car[6] { new car("Ford",1992), new car("Fiat",1988), new car("Buick",1932), new car("Ford",1932), new car("Dodge",1999), new car("Honda",1977) }; } //private enumerator class private class MyEnumerator:IEnumerator { public car[] carlist; int position = -1; //constructor public MyEnumerator(car[] list) { carlist=list; } private IEnumerator getEnumerator() { return (IEnumerator)this; } //IEnumerator public bool MoveNext() { position++; return (position < carlist.Length); } //IEnumerator public void Reset() { position = -1; } //IEnumerator public object Current { get { try { return carlist[position]; } catch (IndexOutOfRangeException) { throw new InvalidOperationException(); } } } } //end nested class public IEnumerator GetEnumerator() { return new MyEnumerator(carlist); } } }
首先、集合必须继承IEnumerable 接口,该接口就是告诉别人他是可以枚举的,他的内部已经实现了枚举器。别人可以通过IEnumerable 接口 提供的GetEnumerator()方法获得枚举器。然后通过枚举器的movenext访问集合成员。
第二、然后需要在集合类的内部放一个枚举器(嵌套一个现实 IEnumerator接口 的类)。然把集合自身的单向链表传入枚举器,枚举器就像放在链表上的游标。
第三、别人就可以通过获取调用集合类的GetEnumerator()方法,获取到集合类的枚举器。通过枚举器顺序的访问集合。
实现IEnumerable接口的类有哪些:
数组、集合类 等等