IEnumerable接口顾名思义就是 可枚举的,可列举的。
接口也很简单,返回一个 枚举器对象 IEnumerator 。
1 [ComVisible(true), Guid("496B0ABE-CDEE-11d3-88E8-00902754C43A")] 2 public interface IEnumerable 3 { 4 [DispId(-4)] 5 IEnumerator GetEnumerator(); 6 } 7 8 9 10
1. IEnumerable 与 IEnumerator
IEnumerable只有一个抽象方法:GetEnumerator(),而IEnumerator又是一个迭代器,真正实现了访问集合的功能。 IEnumerator只有一个Current属性,MoveNext和Reset两个方法。
有个小问题,只搞一个访问器接口不就得了?为什么要两个看起来很容易混淆的接口呢?一个叫枚举器,另一个叫迭代器。因为
1) 实现IEnumerator是个脏活累活,白白加了两个方法一个属性,而且这两个方法其实并不好实现(后面会提到)。
(2) 它需要维护初始状态,知道如何MoveNext ,如何结束,同时返回迭代的上一个状态,这些并不容易。
(3)迭代显然是非线程安全的,每次IEnumerable都会生成新的IEnumerator,从而形成多个互相不影响的迭代过程。在迭代过程中,不能修改迭代集合,否则不安全。
所以只要你实现了IEnumerable,编译器就会帮我们实现IEnumerator。何况绝大多数情况都是从现有集合继承,一般不需要重写MoveNext和Reset方法。 IEnumerable当然还有泛型实现,这个不影响问题的讨论。
IEnumerable也有它的缺点,它没法后退,没法跳跃(只能一个一个的跳过去),而且实现Reset并不容易,无法实现索引访问。想想看, 如果是一个实例集合的枚举过程,直接返回到第0个元素就可以了,但是如果这个IEnumerable是漫长的访问链条,想找到最初的根是很困难的!所 以CLR via C#的作者告诉你,其实很多Reset的实现根本就是谎言,知道有这个东西就行了,不要太过依赖它。
具体实现请看我的另外一篇文章 http://www.cnblogs.com/yplong/p/5286906.html