今天我們說下C#中的迭代器,首先引出一些關於迭代的概念,後面舉出代碼供大家討論。
迭代器模式是行為模式的一種范例,行為模式是一種簡化對象之間通信的一種設計模式。在.NET中使用IEnumerator和IEnumerable接口及它們的泛型等價物來封裝的,如果一個類型實現了IEnumerable接口,就說明它是可迭代的,調用GetEnumerator方法返回IEnumerator的實現,這是迭代器本身。
C#1使用foreach語句實現了訪問迭代器的內置支持,foreach語句會被編譯成使用GetEnumerator和MoveNext方法以及Current屬性。C#中迭代器只能向後訪問,而C++中迭代器可以支持前後訪問。
背景,假設有一個關於學生的隊列,每個學生依次報出自己的名字,Student類如下
1 class Student
2 {
3 public string Name { get; set; }
4
5 public Student(string name)
6 {
7 Name = name;
8 }
9
10 public void SayName()
11 {
12 Console.WriteLine(Name);
13 }
14 }
有一個實現IEnumerable的Queue的泛型類,如下
1 class Queue<T> : IEnumerable<T> where T : class
2 {
3 public List<T> objects = new List<T>();
4
5 public Queue(List<T> list)
6 {
7 objects = list;
8 }
9
10 //實現從IEnumerable中的GetEnumerator方法
11 /*
12 個人覺得這個方法在迭代中只會調用一次,不然每次都返回一個新的QueueIterator<T>對象,位置記錄都會重置為-1
13 */
14 public IEnumerator<T> GetEnumerator()
15 {
16 return new QueueIterator<T>(this);
17 }
18
19 IEnumerator IEnumerable.GetEnumerator()
20 {
21 throw new NotImplementedException();
22 }
23 }
使用GetEnumerator方法返回一個迭代器,而迭代器需要實現IEnumerator接口,如下
1 class QueueIterator<T> : IEnumerator<T> where T : class
2 {
3 private ConsoleDemo.Chapter6.Queue<T> q = null;
4
5 int startPoint = -1; //用於保存游標的位置
6
7 public QueueIterator(ConsoleDemo.Chapter6.Queue<T> q)
8 {
9 this.q = q;
10 }
11
12 //返回合適位置上的T類型實例,這個例子中調用提這個自動屬性
13 public T Current
14 {
15 get
16 {
17 if (startPoint==-1 || startPoint==q.objects.Count)
18 {
19 throw new InvalidOperationException();
20 }
21 int index = startPoint + q.objects.Count;
22 index = index % q.objects.Count;
23 return q.objects[index];
24 }
25 }
26
27 object IEnumerator.Current
28 {
29 get
30 {
31 if (startPoint == -1 || startPoint == q.objects.Count)
32 {
33 throw new InvalidOperationException();
34 }
35 int index = startPoint + q.objects.Count;
36 index = index % q.objects.Count;
37 return q.objects[index];
38 }
39 }
40
41 public void Dispose()
42 {
43
44 }
45
46 public bool MoveNext()
47 {
48 if (startPoint != q.objects.Count)
49 {
50 startPoint++;
51 }
52 return startPoint < q.objects.Count;
53 }
54 //當迭代結束後,會調用這個方法,則下一次迭代後重新從第一個位置開始
55 public void Reset()
56 {
57 startPoint = -1;
58 }
59 }
分別要去實現從IEnumerator中的Current屬性、Dispose方法(有必要的話)、MoveNext方法、Reset方法。使用C#2中的yield語句可以簡化迭代器,再下一篇中再說。
請斧正。