迭代器也是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 Friend17 {18 private string name;19 public string Name20 {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 : IEnumerable32 {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接口的方法51 public IEnumerator GetEnumerator()52 {53 return new FriendIterator(this);54 }55 }56 57 public class FriendIterator : IEnumerator58 {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 else75 {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 Friend17 {18 private string name;19 public string Name20 {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 : IEnumerable32 {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接口的方法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#提供的一种方便形式),它简化了我们的迭代器源代码,把具体而复杂的实现过程留给了编译器去完成。