Enumerable接口允许使用foreach循环。在foreach循环中并不是只能使用集合类,相反,在foreach循环中使用定制类通常有很多优点。
但是,重写使用foreach循环的方式或者提供定制的实现方式并不一定很简单。为了说明这一点,下面有必要深入研究一下foreach循环。在foreach循环中,迭代一个collectionObject集合的过程如下:
(1)调用 collectionObjectGetEnumeratorO,返回一个Enumerator引用。这个方法可通过IEnumerable接口的实现代码来获得,但这是可选的。
(2)调用所返回的IEnumerator接口的MoveNextQ方法。
(3)如果MoveNextO方法返回true,就使用IEnumerator接口的Current属性来获取对象的一个引用,用于 foreach 循环。
(4)重复前面两步,直到MoveNextO方法返回felse为止,此时循环停止。
所以,为在类中进行这些操作,必须重写几个方法,跟踪索引,维护Qirrent属性,以及执行其他一些操作。这要做许多工作。
—个较简单的替代方法是使用迭代器。使用迭代器将有效地自动生成许多代码,正确地完成所有任务。而且,使用迭代器的语法掌握起来非常容易。
迭代器的定义是,它是一个代码块,按顺序提供了要在foreach块中使用的所有值。一般情况下,这个代码块是一个方法,但也可以使用属性访问器和其他代码块作为迭代器。这里为简单起见,仅介绍方法。
无论代码块是什么,其返回类型都是有限制的。与期望正好相反,这个返回类型与所枚举的对象类型不同。例如,在表示Animal对象集合的类中,迭代器块的返回类型不可能是Animal。两种可能的返回类型是前面提到的接口类型:IEnumerable和IEnumerator。使用这两种类型的场合是:
•如果要迭代一个类,则使用方法GetEnumerator(),其返回类型是IEnumerator。
•如果要迭代一个类成员,例如一个方法,则使用IEnumerable。
在迭代器块中,使用yield关键字选择要在foreach循环中使用的值。其语法如下:
yield return <value>;
利用这个信息就足以建立一个非常简单的示例,如下所示(该示例包含在代码文件SimpleIterators\Program.cs中):
public static IEnumerable SimpleList()
{
yield return "string 1";
yield return "string 2";
yield return "string 3";
}
static void Main(string[] args)
{
foreach (string item in SimpleList())
WriteLine (item);
ReadKey();
}
在此,静态方法SimpleListO就是迭代器块。它是一个方法,所以使用IEnumerable返回类型。SimpleList()使用yieid关键字为使用它的foreach块提供了 3个值,每个值都输出到屏幕上,结果如图所示。
显然,这个迭代器并不是特别有用,但它确实能够演示迭代器的机制,说明实现迭代器有多么简单。看看代码,读者可能会疑惑代码是如何知道返回string类型的项。实际上,并没有返回string类型的项,而是返回object类型的值。因为object是所有类型的基类,所以可从yield语句中返回任意类型。
但编译器的智能程度很高,所以我们可以把返回值解释为foreach循环需要的任何类型。这里代码需要string类型的值,而这正是我们要使用的值。如果修改一行yield代码,让它返回一个整数,就会在foreach循环中出现一个类型转换异常。
对于迭代器,还有一点要注意。可以使用下面的语句中断将信息返回给foreach循环的过程:
yield break;
在遇到迭代器中的这个语句时,迭代器的处理会立即中断,使用该迭代器的foreach循环也一样。
已有 22658 名学员学习以下课程通过考试
最需教育客户端 软件问题一手掌握
去 App Store 免费下载 iOS 客户端
点击加载更多评论>>