19.4 迭代器

迭代器可以使我们自定义的类或结构支持使用foreach迭代,而不必实现IEnumerable接口。虽然该接口只定义了一个接口方法,如下:


public interface IEnumerable

{

IEnumerator GetEnumerator();

}


可见,IEnumerable接口的唯一方法就是返回一个IEnumerator接口类型,IEnumerator接口的定义如下:


public interface IEnumerator

{

bool MoveNext();

object Current{get;}

void Reset();

}


foreach语句会通过GetEnumerator方法返回IEnumerator类型的数据,然后调用MoveNext来完成对集合的遍历,其中Current是遍历过程中的每个集合元素数据,可见它是一个只读的属性。

刚讲的是非泛型的IEnumerable和IEnumerator接口,它们的泛型版本功能相同,只不过抽象了数据类型,添加了类型参数,定义如下:


public interface IEnumerable<T>:IEnumerable

{

IEnumerator<T>GetEnumerator();

}

public interface IEnumerator<T>:IDisposable,IEnumerator

{

T Current{get;}

}


讲完了IEnumerable接口和IEnumerator接口,我们继续说迭代器。换句话说,迭代器是除了实现IEnumerable接口以外,另一个支持foreach迭代的方式或者途径。迭代器的作用就是遍历一个类中的数据集合。

一个类或结构中可以定义多个迭代器。当编译器检测到类中存在迭代器时,它将自动生成IEnumerator或IEnumerator<T>接口的Current、MoveNext和Reset方法,如果是泛型版本,还将自动生成Dispose方法,因为IEnumerator<T>接口实现了IDisposable接口。

我们已经对迭代器有了初步了解,这里说明一下它的一些主要特性,如下:

❑可以按照一定顺序返回一系列相同类型的值,如果非泛型版本返回的是System.Object类型,泛型版本则返回的T类型;

❑迭代器使用yield return语句依次返回集合中的每个元素数据;

❑yield语句只能出现在迭代块中,该块可存在于方法、运算符或get访问器的代码块中。但有一个限制,就是方法、运算符或访问器的参数不能是ref或out,另外也不能放在匿名方法中。

要创建一个迭代器,最常用的方法是实现IEnumerable接口,并实现GetEnumerator方法,也可以不实现IEnumerable接口,而直接提供GetEnumerator方法,例如:


public IEnumerator<string>GetEnumerator()

{

foreach(string lesson in Lessons)

{

yield return lesson;

}

}


如果要在一个类中提供多个迭代器,其他的迭代器应该返回IEnumerable类型,例如:


public IEnumerable<string>Interests

{

get

{

foreach(string interest in interests)

{

yield return interest;

}

}

}


可以在同一个迭代器中使用多个yield语句,如下面的示例所示:


public System.Collections.IEnumerator GetEnumerator()

{

yield return“语文”;

yield return“数学”;

yield return“外语”;

yield return“物理”;

}


代码清单19-16 演示了迭代器的使用,注意提供迭代器的类Student并没有实现IEnumerable<T>接口,这里使用非泛型的IEnumerable也是一样的。在Student类中我们提供了两个迭代器,其中第2个是通过get访问器提供的。

代码清单19-16 迭代器代码示例


using System;

using System.Collections.Generic;

namespace ProgrammingCSharp4

{

class CollectionSample

{

public static void Main()

{

Student student=new Student();

Console.WriteLine(“课程:”);

Console.WriteLine("-".PadLeft(10,'-'));

foreach(string lesson in student)

{

Console.WriteLine(lesson);

}

Console.WriteLine();

Console.WriteLine(“爱好:”);

Console.WriteLine("-".PadLeft(10,'-'));

foreach(string interest in student.Interests)

{

Console.WriteLine(interest);

}

}

public class Student

{

public string[]Lessons=new string[]{“语文”,“数学”,“外语”,“物理”,“化学”};

public string[]interests=new string[]{“上网”,“听歌”,“看电影”};

public IEnumerator<string>GetEnumerator()

{

foreach(string lesson in Lessons)

{

yield return lesson;

}

}

public IEnumerable<string>Interests

{

get

{

foreach(string interest in interests)

{

yield return interest;

}

}

}

}

}

}


上述代码的运行结果为:


课程:


语文

数学

外语

物理

化学

爱好:


上网

听歌

看电影

请按任意键继续……