using System;
using System.Collections;
关于使用IEnumerable、IEnumerator以及yield return来实现对foreach语句的支持,参见:《C#枚举器:foreach语句、IEnumerable、IEnumerator以及yield return (一)》
本文主要是分析一下foreach语句本身:
foreach (var item in collection) { //do someth }
foreach语句要求遍历的对象collection实现GetEnumerator方法(这个方法定义在IEnumerable中),所以foreach语句工作时其实是转化成了如下语句来迭代collection中的每个元素的:
IEnumerator enumerator = colloction.GetEnumerator(); while(enumerator.MoveNext()) { var item = enumerator.Current; //do something }
事实上,这里的collection可以替换成任何实现了GetEnumerator()方法的对象,或者一个表达式且该表达最终返回一个实现了GetEnumerator()方法的对象,比如
//假设myArray.Reverse()返回一个继承自IEnumerable接口的对象,或者实现了GetEnumerator()方法的对象 foreach (var item in myArray.Reverse()) { //do something }
了解到这一点后,我们可以按照自己的想法去充分挖掘foreach迭代的用法,例如
public class Names:IEnumerable { string[] names = { "David", "Peter", "Kunta", "Linda", "Bob" }; //基本迭代 public IEnumerator GetEnumerator() { for (int i = 0; i < 5; i++) { yield return names[i]; } } //逆序迭代 public IEnumerable Reverse() { for (int i = 4; i >= 0; i--) { yield return names[i]; } } //部分迭代 public IEnumerable Subset(int startIndex, int length) { for (int i = startIndex; i < startIndex + length; i++) { yield return names[i]; } } } public class TestNames { public static void Test() { var names = new Names(); foreach (var name in names)//基本迭代的调用 { Console.WriteLine(name); } foreach (var name in names.Reverse())//逆序迭代的调用 { Console.WriteLine(name); } foreach (var name in names.Subset(2,2))//部分迭代的调用 { Console.WriteLine(name); } Console.ReadKey(); } }
按照前面的所说的:
①第一个基本迭代的对象是names,foreach会最终去调用names.GetEnumerator(),这种是我们定义在Names类中的方法;
②第二个逆序迭代的对象是names.Reverse(),该方法返回IEnumerable接口,肯定是实现了GetEnumerator()方法的,因此foreach语句会最终去调用names.Reverse().GetEnumerator(),而这里这个GetEnumerator()并不是我们在Names类中实现的方法,而是yield return语句自动生成的;
③第三个与第二个一样,foreach语句最终会调用names.Subset(2, 2).GetEnumerator();