基础【循环】-------(IEnumerable和IEnumerator(包括泛型版))------(转)

1. 一个Collection要支持foreach方式的遍历,必须实现IEnumerable接口(亦即,必须以某种方式返回IEnumerator对象)。 
2. IEnumerator对象具体实现了iterator(通过MoveNext(),Reset(),Current)。 
3. 从这两个接口的用词选择上,也可以看出其不同:IEnumerable是一个声明式的接口,声明实现该接口的class是“可枚举(enumerable)”的,但并没有说明如何实现枚举器(iterator)IEnumerator是一个实现式的接口,IEnumerator对象就是一个iterator(迭代器)。 
4. IEnumerable和IEnumerator通过IEnumerable的GetEnumerator()方法建立了连接,可以通过IEnumerable的GetEnumerator()得到IEnumerator对象。
5. 由于IEnumerable<T>扩展(继承)了旧的IEnumerable接口,所以要实现两个不同的方法
IEnumerator<T> GetEnumerator();
IEnumerator GetEnumerator(); // 由于和泛型版本的方法同名,所以该方法的实现需要使用显式接口实现
      为什么集合类不直接继承(支持)IEnumerator<T>和IEnumerator接口?
      假如同时有两个循环交错遍历同一个集合(一个foreach嵌套了另外一个foreach),那么集合必须维持当前元素的一个状态指示器,确保当调用MoveNext()方法时,能正确定位下一个元素。
      为了解决这个问题,集合类不直接支持IEnumerator<T>和IEnumerator接口。而是通过IEnumerable的GetEnumerator返回一个新的IEnumerator对象来负责维护循环遍历的状态,IEnumerator(迭代器,或者叫枚举数)相当于一个“游标”(cursor)或者“书签”。可以有多个书签,移动每个书签都可独立于其他书签来遍历集合。
 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             CountingEnumerable counter = new CountingEnumerable();
 6             foreach (int x in counter)
 7             {
 8                 Console.WriteLine(x);
 9             }
10  
11             Console.ReadKey();
12         }
13     }
14  
15     class CountingEnumerable : IEnumerable<int>
16     {
17         public IEnumerator<int> GetEnumerator()
18         {
19             return new CountingEnumerator(); // 返回一个新的迭代器,是为了维护状态
20         }
21  
22         // 由于IEnumerable<T>继承IEnumerable,两个接口的GetEnumerator方法同名
23         // 所以对于非泛型的IEnumerable的GetEnumerator方法使用显式接口实现。
24         // (如果IEnumerable<T>没有继承IEnumerable,那么一个只支持使用非泛型IEnumerable的
25         // 方法将无法使用IEnumerable<T>)
26         IEnumerator IEnumerable.GetEnumerator()
27         {
28             return GetEnumerator(); // IEnumerator是IEnumerator<T>的基类
29         }
30     }
31  
32     class CountingEnumerator : IEnumerator<int>
33     {
34         int current = -1;
35  
36         public bool MoveNext()
37         {
38             current++;
39             return current < 10;
40         }
41  
42         public int Current { get { return current; } }
43  
44         object IEnumerator.Current { get { return Current; } }
45  
46         public void Reset()
47         {
48             current = -1;
49         }
50  
51         // IEnumerator<T>继承了IDisposable,为了遍历完后清理状态,所以需要实现该方法
52         // 该方法在foreach循环完毕后自动调用
53         public void Dispose() { } 
54     }
55   
View Code

 

posted @ 2013-11-21 14:26  行进  阅读(369)  评论(0编辑  收藏  举报