迭代器也是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#提供的一种方便形式),它简化了我们的迭代器源代码,把具体而复杂的实现过程留给了编译器去完成。