一、Foreach语句简介
在C# 1.0中我们经常使用foreach来遍历一个集合中的元素,然而如果一个集合要支持使用foreach语句来进行遍历,这个集合一般需要IEnumerable或IEnumerable<T>接口。
因为foreach是迭代语句,要使用foreach必须要有一个迭代器才行的,而IEnumerable接口中的IEnumerator GetEnumerator()方法是返回迭代器的。
在C# 1.0中,要获得迭代器一般需要实现IEnumerable接口中的GetEnumerator()方法,然而要实现一个迭代器就必须实现IEnumerator接口。
在C# 2.0中,提供 yield关键字来简化迭代器的实现。
foreach被编译后会调用GetEnumerator来返回一个迭代器。
二、C#1.0中实现迭代器
1 using System; 2 using System.Collections; 3 4 namespace 迭代器Demo 5 { 6 class Program 7 { 8 static void Main(string[] args) 9 { 10 Friends friendcollection = new Friends(); 11 foreach (Friend f in friendcollection) 12 { 13 Console.WriteLine(f.Name); 14 } 15 16 Console.Read(); 17 } 18 } 19 20 /// <summary> 21 /// 朋友类 22 /// </summary> 23 public class Friend 24 { 25 private string name; 26 public string Name 27 { 28 get { return name; } 29 set { name = value; } 30 } 31 public Friend(string name) 32 { 33 this.name = name; 34 } 35 } 36 37 /// <summary> 38 /// 朋友集合 39 /// </summary> 40 public class Friends : IEnumerable 41 { 42 private Friend[] friendarray; 43 44 public Friends() 45 { 46 friendarray = new Friend[] 47 { 48 new Friend("张三"), 49 new Friend("李四"), 50 new Friend("王五") 51 }; 52 } 53 54 // 索引器 55 public Friend this[int index] 56 { 57 get { return friendarray[index]; } 58 } 59 60 public int Count 61 { 62 get { return friendarray.Length; } 63 } 64 65 // 实现IEnumerable<T>接口方法 66 public IEnumerator GetEnumerator() 67 { 68 return new FriendIterator(this); 69 } 70 } 71 72 /// <summary> 73 /// 自定义迭代器,必须实现 IEnumerator接口 74 /// </summary> 75 public class FriendIterator : IEnumerator 76 { 77 private readonly Friends friends; 78 private int index; 79 private Friend current; 80 internal FriendIterator(Friends friendcollection) 81 { 82 this.friends = friendcollection; 83 index = 0; 84 } 85 86 #region 实现IEnumerator接口中的方法 87 public object Current 88 { 89 get 90 { 91 return this.current; 92 } 93 } 94 95 public bool MoveNext() 96 { 97 if (index + 1 > friends.Count) 98 { 99 return false; 100 } 101 else 102 { 103 this.current = friends[index]; 104 index++; 105 return true; 106 } 107 } 108 109 public void Reset() 110 { 111 index = 0; 112 } 113 114 #endregion 115 } 116 }
三、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 f in friendcollection) 9 { 10 Console.WriteLine(f.Name); 11 } 12 13 Console.Read(); 14 } 15 } 16 17 /// <summary> 18 /// 朋友类 19 /// </summary> 20 public class Friend 21 { 22 private string name; 23 public string Name 24 { 25 get { return name; } 26 set { name = value; } 27 } 28 public Friend(string name) 29 { 30 this.name = name; 31 } 32 } 33 34 /// <summary> 35 /// 朋友集合 36 /// </summary> 37 public class Friends : IEnumerable 38 { 39 private Friend[] friendarray; 40 41 public Friends() 42 { 43 friendarray = new Friend[] 44 { 45 new Friend("张三"), 46 new Friend("李四"), 47 new Friend("王五") 48 }; 49 } 50 51 // 索引器 52 public Friend this[int index] 53 { 54 get { return friendarray[index]; } 55 } 56 57 public int Count 58 { 59 get { return friendarray.Length; } 60 } 61 62 // C# 2.0中简化迭代器的实现 63 public IEnumerator GetEnumerator() 64 { 65 for (int index = 0; index < friendarray.Length; index++) 66 { 67 // 这样就不需要额外定义一个FriendIterator迭代器来实现IEnumerator 68 // 在C# 2.0中只需要使用下面语句就可以实现一个迭代器 69 yield return friendarray[index]; 70 } 71 } 72 } 73 }
在上面代码中有一个yield return 语句,这个语句的作用就是告诉编译器GetEnumerator方法不是一个普通的方法,而是实现一个迭代器的方法。
当编译器看到yield return语句时,编译器知道需要实现一个迭代器,所以编译器生成中间代码时为我们生成了一个实现IEnumerator接口的内部类。
大家可以通过Reflector工具进行查看,下面是通过Reflector工具得到一张截图:
四、迭代器执行过程
注:本文参考http://www.cnblogs.com/zhili/archive/2012/12/02/Interator.html