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;
}
}
}
}
}
}
上述代码的运行结果为:
课程:
语文
数学
外语
物理
化学
爱好:
上网
听歌
看电影
请按任意键继续……