IEnumerable及IEnumerable的泛型版本IEnumerable
实现了这个接口的类可以使用Foreach关键字进行迭代(迭代的意思是对于一个集合,可以逐一取出元素并遍历之)。实现这个接口必须实现方法GetEnumerator。
实现一个继承IEnumerable的类型等同于实现方法GetEnumerator。想知道如何实现方法GetEnumerator,不妨思考下实现了GetEnumerator之后的类型在Foreach之下的行为:
假设我们有一个很简单的Person类(例子来自MSDN):
publicclassPerson{publicPerson(stringfName,stringlName){FirstName=fName;LastName=lName;}publicstringFirstName;publicstringLastName;}然后我们想构造一个没有实现IEnumerable的类型,其储存多个Person,然后再对这个类型实现IEnumerable。这个类型实际上的作用就相当于Person[]或List
//People类就是Person类的集合//但我们不能用List
publicstaticvoidMain(string[]args){//新的Person数组Person[]peopleArray={newPerson("John","Smith"),newPerson("Jim","Johnson"),newPerson("Sue","Rabon"),};//People类实现了IEnumerablevarpeopleList=newPeople(peopleArray);//枚举时先访问MoveNext方法//如果返回真,则获得当前对象,返回假,就退出此次枚举foreach(PersonpinpeopleList)Console.WriteLine(p.FirstName+""+p.LastName);}复制代码但现在我们的程序不能运行,因为我们还没实现GetEnumerator方法。
GetEnumerator方法需要一个IEnumerator类型的返回值,这个类型是一个接口,所以我们不能这样写:
returnnewIEnumerator();因为我们不能实例化一个接口。我们必须再写一个类PeopleEnumerator,它继承这个接口,实现这个接口所有的成员:Current属性,两个方法MoveNext和Reset。于是我们的代码又变成了这样:
//实现IEnumerable需要实现GetEnumerator方法publicIEnumeratorGetEnumerator(){returnnewPeopleEnumerator();}在类型中:
publicclassPeopleEnumerator:IEnumerator{publicboolMoveNext(){thrownewNotImplementedException();}publicvoidReset(){thrownewNotImplementedException();}publicobjectCurrent{get;}}现在问题转移为实现两个方法,它们的功能看上去一目了然:一个负责将集合中Current向后移动一位,一个则将Current初始化为0。我们可以查看IEnumerator元数据,其解释十分清楚:
通过上面的文字,我们可以理解GetEnumerator方法,就是获得当前Enumerator指向的成员。我们引入一个整型变量position来记录当前的位置,并且先试着写下:
publicclassPeopleEnumerator:IEnumerator{publicPerson[]_peoples;publicobjectCurrent{get;}//当前位置publicintposition;//构造函数接受外部一个集合并初始化自己内部的属性_peoplespublicPeopleEnumerator(Person[]peoples){_peoples=peoples;}//如果没到集合的尾部就移动position,返回一个boolpublicboolMoveNext(){if(position<_peoples.Length){position++;returntrue;}returnfalse;}publicvoidReset(){position=0;}}
这看上去好像没问题,但一执行之后却发现:
通过不断的调试,最后完整的实现应当是:
publicclassPeopleEnumerator:IEnumerator{publicPerson[]People;//每次运行到MoveNext或Reset时,利用get方法自动更新当前位置指向的对象objectIEnumerator.Current{get{try{//当前位置的对象returnPeople[_position];}catch(IndexOutOfRangeException){thrownewInvalidOperationException();}}}//当前位置privateint_position=-1;publicPeopleEnumerator(Person[]people){People=people;}//当程序运行到foreach循环中的in时,就调用这个方法获得下一个person对象publicboolMoveNext(){_position++;//返回一个布尔值,如果为真,则说明枚举没有结束。//如果为假,说明已经到集合的结尾,就结束此次枚举return(_position
foreach(Titemincollection){...}IEnumerator