C#中的迭代器

迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象内部的表示。迭代器为遍历不同的聚集结构提供如开始、下一个、是否结束、当前哪一项等统一的借口。

迭代器模式结构图:

Iterator类

复制代码
/////////////////////////////////////////////////////////////  Iterator.cs //  Implementation of the Class Iterator //  Generated by Enterprise Architect //  Created on:      23-七月-2011 13:44:42 //  Original author: xinyuanzhang///////////////////////////////////////////////////////////
namespace Test { ///<summary>/// 迭代抽象类 ///</summary>publicabstractclass Iterator {
public Iterator() {
}
~Iterator() {
}
publicvirtualvoid Dispose() {
}
publicabstractobject CurrentItem();
publicabstractobject First();
publicabstractbool IsDone();
publicabstractobject Next();
}
//end Iterator}
复制代码

Aggregate聚集抽象类

复制代码
/////////////////////////////////////////////////////////////  Aggregate.cs //  Implementation of the Class Aggregate //  Generated by Enterprise Architect //  Created on:      23-七月-2011 13:46:01 //  Original author: xinyuanzhang///////////////////////////////////////////////////////////
namespace Test { ///<summary>/// 聚集抽象类 ///</summary>publicabstractclass Aggregate {
public Aggregate() {
}
~Aggregate() {
}
publicvirtualvoid Dispose() {
}
publicabstract Iterator CreateIterator();
}
//end Aggregate}
复制代码

ConcreteIterato具体迭代器类

复制代码
/////////////////////////////////////////////////////////////  ConcreteIterator.cs //  Implementation of the Class ConcreteIterator //  Generated by Enterprise Architect //  Created on:      23-七月-2011 13:48:10 //  Original author: xinyuanzhang///////////////////////////////////////////////////////////
namespace Test { publicclass ConcreteIterator : Iterator {
//定义有一个具体聚集对象public ConcreteAggregate m_ConcreteAggregate; privateint current =0;
public ConcreteIterator() { }
//初始化聚集对象传入public ConcreteIterator(ConcreteAggregate aggregate) { this.m_ConcreteAggregate = aggregate; }
~ConcreteIterator() {
}
publicoverridevoid Dispose() {
}
///<summary>/// 返回当前聚集对象 ///</summary>///<returns></returns>publicoverrideobject CurrentItem() {
return m_ConcreteAggregate[current]; }
///<summary>/// 得到聚集的第一个对象 ///</summary>///<returns></returns>publicoverrideobject First() {
return m_ConcreteAggregate[0]; }
///<summary>/// 判断当前是否遍历到结尾 ///</summary>///<returns></returns>publicoverridebool IsDone() {
return current >= m_ConcreteAggregate.Count ?true : false; }
///<summary>/// 得到聚集的下一个对象 ///</summary>///<returns></returns>publicoverrideobject Next() {
object ret =null; current++; if (current < m_ConcreteAggregate.Count) { ret = m_ConcreteAggregate[current]; } return ret; }
}
//end ConcreteIterator}
复制代码

ConcreteAggregate具体聚集类

复制代码
/////////////////////////////////////////////////////////////  ConcreteAggregate.cs //  Implementation of the Class ConcreteAggregate //  Generated by Enterprise Architect //  Created on:      23-七月-2011 13:49:53 //  Original author: xinyuanzhang///////////////////////////////////////////////////////////using System.Collections.Generic;
namespace Test { publicclass ConcreteAggregate : Aggregate {
public ConcreteAggregate() {
}
~ConcreteAggregate() {
}
publicoverridevoid Dispose() {
}
publicoverride Iterator CreateIterator() {
returnnew ConcreteIterator(this); }
//声明一个IList<T>变量,用于存放聚合对象private IList<object> items =new List<object>();
//返回集合总个数publicint Count { get { return items.Count; } }
//声明一个索引器publicobjectthis[int index] { get { return items[index]; } set { items.Insert(index, value); } }
}
//end ConcreteAggregate}
复制代码

客户端代码

复制代码
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.Common; using System.Data;
namespace Test { class Program { staticvoid Main(string[] args) { ConcreteAggregate a =new ConcreteAggregate();
a[
0] ="A"; a[1] ="B"; a[2] ="C"; a[3] ="D"; a[4] ="E"; a[5] ="F"; a[6] ="G";
Iterator i
=new ConcreteIterator(a); object item = i.First(); while (!i.IsDone()) { Console.WriteLine(i.CurrentItem()); i.Next(); } Console.ReadKey(); } } }
复制代码

运行结果

在实际使用中.NET框架已经准备好了相关接口,C#支持关键字foreach,允许我们遍历任何数组类型的内容。任何支持GetEnumerator()方法的类型都可以通过foreach结构进行运算。这个方法是由IEnumerable接口定义的。对象支持这种行为说明它们能够向调用方法提供自己包含的子项。

//这个接口告知调用方法的子项可以枚举publicinterface IEnumerable {     IEnumerator GetIEnumerator(); }

GetEnumerator()方法返回一个IEumerator的引用。这个接口提供了基础设施,调用方法可以用来移动IEnumerable兼容容器包含的内部对象:

复制代码
//这个接口允许调用方法获取一个容器的子项publicinterface IEnumerator {     bool MoveNext();//将光标的内部位置向前移动。object Currect{get;}//获取当前的项void Reset();//将光标重置到第一个成员前面}
复制代码

可以修改自定义类型使之支持这些接口,一个更简单的方法是Array和其它许多类型已经实现了这2个接口,可以简单的请求到Array,如下所示:

复制代码
using System; using System.Collections; using System.Linq; using System.Text;
namespace Test { publicclass LetterSet:IEnumerable { private Letter[] letterArr =new Letter[7];
public LetterSet() { letterArr[0] =new Letter(1,"A"); letterArr[1] =new Letter(2,"B"); letterArr[2] =new Letter(3,"C"); letterArr[3] =new Letter(4,"D"); letterArr[4] =new Letter(5,"E"); letterArr[5] =new Letter(6,"F"); letterArr[6] =new Letter(7,"G"); }
public IEnumerator GetEnumerator() { return letterArr.GetEnumerator(); } } }
复制代码

客户端代码

复制代码
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.Common; using System.Data;
namespace Test { class Program { staticvoid Main(string[] args) { LetterSet ls =new LetterSet(); foreach (Letter l in ls) { Console.WriteLine(l.Name); }
Console.ReadKey(); } } }
复制代码

上面还不是最简单的方法,从.Net2.0以后,可以通过迭代器来构建使用foreach的类型。

简单来说,迭代器指定了容器内部项被foreach处理时该如何返回,虽然迭代器方法还是必须命名为GetEnumerator(),返回值还是IEumerator类型,但自定义类不需要实现原来那些接口了:

复制代码
using System; using System.Collections; using System.Linq; using System.Text;
namespace Test { publicclass LetterSet { private Letter[] letterArr =new Letter[7];
public LetterSet() { letterArr[0] =new Letter(1,"A"); letterArr[1] =new Letter(2,"B"); letterArr[2] =new Letter(3,"C"); letterArr[3] =new Letter(4,"D"); letterArr[4] =new Letter(5,"E"); letterArr[5] =new Letter(6,"F"); letterArr[6] =new Letter(7,"G"); }
public IEnumerator GetEnumerator() { foreach (Letter l in letterArr) { yieldreturn l; } } } }
复制代码

例中上GetEnumerator()的实现使用内部foreach逻辑迭代每个项,使用yield返回语法后,当前位置被存储下来,下次调用迭代器会从这个位置开始执行。也可以不使用foreach关键字,下面的用法并不推荐,因为当实例增多时,GetEnumerator()就不会同步,但是该方法的运行结果可以帮助我们理解yield关键字。

复制代码
     public IEnumerator GetEnumerator()         {             yieldreturn letterArr[0];             yieldreturn letterArr[1];             yieldreturn letterArr[2];             yieldreturn letterArr[3];             yieldreturn letterArr[6];             yieldreturn letterArr[5];             yieldreturn letterArr[4];         }
复制代码

运行结果如下:

yield关键字可以和任何方法一起使用,这些方法也被称为“命名迭代器”,其独特之处在于可以接受参数。构建命名迭代器时,这些方法必须定义为返回IEnumerable类型,而不是IEumerator类型,下例显示了一个通过参数决定排列顺序的方法:

复制代码
public IEnumerable GetLetters(bool IsASC)         {             if (IsASC)             {                 foreach (Letter l in letterArr)                 {                     yieldreturn l;                 }             }             else             {                 for (int i = letterArr.Length; i !=0; i--)                 {                     yieldreturn letterArr[i -1];                 }             }         }
复制代码

客户端代码

foreach (Letter l in ls.GetLetters(false))             {                 Console.WriteLine(l.Name);             }

运行结果

命名迭代器是很有用的结构,因为一个自定义容器可以定义多重方式来请求返回的集。

出处:http://www.cnblogs.com/MeteorSeed/archive/2011/07/23/2098659.html

原文地址:https://www.cnblogs.com/movemoon/p/2805262.html