迭代器也是C# 2.0的產物。
1.1 迭代器的簡介
迭代器記錄了集合中的某個位置,它使程序只能向前移動。C# 1.0中使用foreach語句來實現訪問迭代器的內置支持,foreach使遍歷集合變得簡單,它比for語句更方便,也更容易理解。foreach被編譯器編譯後,會調用GetEnumerator來返回一個迭代器,也就是一個集合中的初始位置。
1.2 C# 1.0中如何實現迭代器
一個類型想要使用foreach關鍵字進行遍歷,它必須實現IEnumerable或IEnumerable<T>接口。IEnumerable接口中定義了一個GetEnumerator方法用來返回迭代器,類型如果實現了IEnumerable接口,則也必須實現GetEnumerator方法。
1 namespace 迭代器 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 Friends friendcollection=new Friends(); 8 foreach (Friend friend in friendcollection) 9 { 10 Console.WriteLine(friend.Name); 11 } 12 Console.ReadKey(); 13 } 14 } 15 16 public class Friend 17 { 18 private string name; 19 public string Name 20 { 21 get { return name; } 22 set { name = value; } 23 } 24 25 public Friend(string name) 26 { 27 this.name = name; 28 } 29 } 30 31 public class Friends : IEnumerable 32 { 33 private Friend[] friendarray; 34 35 public Friends() 36 { 37 friendarray=new Friend[] 38 { 39 new Friend("張三"), 40 new Friend("李四"), 41 new Friend("王五"), 42 }; 43 } 44 45 //索引器 46 public Friend this[int index] => friendarray[index]; 47 48 public int Count => friendarray.Length; 49 50 //實現IEnumerable<T>接口的方法 51 public IEnumerator GetEnumerator() 52 { 53 return new FriendIterator(this); 54 } 55 } 56 57 public class FriendIterator : IEnumerator 58 { 59 private readonly Friends friends; 60 private int index; 61 private Friend current; 62 internal FriendIterator(Friends friendcollection) 63 { 64 this.friends = friendcollection; 65 index = 0; 66 } 67 68 public bool MoveNext() 69 { 70 if (index + 1 > friends.Count) 71 { 72 return false; 73 } 74 else 75 { 76 this.current = friends[index]; 77 index++; 78 return true; 79 } 80 } 81 82 public void Reset() 83 { 84 index = 0; 85 } 86 //實現IEnumerator接口中的方法 87 public object Current => this.current; 88 89 } 90 }
從以上的代碼可以看出,在C# 1.0中,要使用某個類型可以迭代是需要寫大量代碼的。
1.3 C# 2.0簡化了迭代器的實現
不說這麼多,直接上代碼:
1 namespace 迭代器 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 Friends friendcollection=new Friends(); 8 foreach (Friend friend in friendcollection) 9 { 10 Console.WriteLine(friend.Name); 11 } 12 Console.ReadKey(); 13 } 14 } 15 16 public class Friend 17 { 18 private string name; 19 public string Name 20 { 21 get { return name; } 22 set { name = value; } 23 } 24 25 public Friend(string name) 26 { 27 this.name = name; 28 } 29 } 30 31 public class Friends : IEnumerable 32 { 33 private Friend[] friendarray; 34 35 public Friends() 36 { 37 friendarray=new Friend[] 38 { 39 new Friend("張三"), 40 new Friend("李四"), 41 new Friend("王五"), 42 }; 43 } 44 45 //索引器 46 public Friend this[int index] => friendarray[index]; 47 48 public int Count => friendarray.Length; 49 50 //實現IEnumerable<T>接口的方法 51 public IEnumerator GetEnumerator() 52 { 53 for (int index = 0; index < friendarray.Length; index++) 54 { 55 //在C# 2.0中,只需要使用下面的語句就可以實現一個迭代器 56 yield return friendarray[index]; 57 } 58 } 59 } 60 }
這段代碼只用了一個yield return就完成了迭代器的實現,它作用就是在告訴編譯器,GetEnumerator方法不是一個普通的方法,而是實現迭代器的方法。當編譯器看到yield return 語句時,會在中間代碼中為我們生成了一個IEnumerator接口的對象。可以使用反射工具Reflector看一下。
由上圖可以看出,yield return語句其實是C#中提供的另一個語法糖(語法糖可以理解為C#提供的一種方便形式),它簡化了我們的迭代器源代碼,把具體而復雜的實現過程留給了編譯器去完成。