迭代器
C# 迭代器 迭代器概述 迭代器是可以返回相同类型的值的有序序列的一段代码。 迭代器可用作方法、运算符或 get 访问器的代码体。 迭代器代码使用 yield return 语句依次返回每个元素。yield break 将终止迭代。有关更多信息,请参见 yield。 可以在类中实现多个迭代器。每个迭代器都必须像任何类成员一样有唯一的名称,并且可以在 foreach 语句中被客户端代码调用,如下所示:foreach(int x in SampleClass.Iterator2){} 迭代器的返回类型必须为 IEnumerable、IEnumerator、IEnumerable<T> 或 IEnumerator<T>。 迭代器是使用在foreach中的集合。在C#2.0中使用迭代器创建一个用于foreach的集合,实现上比较简单:继承于IEumnerable,并实现GetEnumerator()。 首先这个集合要基于IEnumerable(可以使用泛型),下面先来实现一个非泛型版的迭代器。代码如下(非泛型代码示例来源于MSDN): public class DaysOfTheWeek : System.Collections.IEnumerable public System.Collections.IEnumerator GetEnumerator() 操作结果是: Sun Mon Tue Wed Thr Fri Sat 其中yied return关键字产生枚举元素 泛型版迭代器的实现代码如下: static void Main(string[] args) Stack<int> stack = new Stack<int>(); public class Stack<T> : IEnumerable<T> public IEnumerator<T> GetEnumerator() IEnumerator IEnumerable.GetEnumerator() 运行结果如下: 1 其中G在实现泛型迭代器时我一直没有写IEnumerator IEnumerable.GetEnumerator()这个方法,所以编译器一直在给我报错,(猜想)这个方法应该IEnumerator<T>接口中的一个抽象方法。而这个方法中调用的GetEnumerator(),通过集成环境中的提示发现,实际上是上面写到的IEnumerator<T> GetEnumerator()这个泛型方法。 在自定义迭代器时,我们可以利用yield break关键字跳出循环。如上面的例子中,我们想只输出小于等于5的项,调整上面代码,如: public class Stack<T> : IEnumerable<T> public IEnumerator<T> GetEnumerator() for (int i = 0; i < items.Length; i++) if ((Convert.ToInt32(items[i]) > 5)) yield return items[i]; IEnumerator IEnumerable.GetEnumerator() 操作结果: 1 迭代器的机制: 实际上迭代器只是在C#2.0中通过编译器一层额外处理的,用来简化创建可用于foreach的枚举集合的工作,从性能上没有什么变化。对于其生成的中间语言没有太多的变化。 class Class1 // 定义一个命名的迭代器,并可以提供参数 // 定义一个迭代器类型的属性, public IEnumerable GetDescriptions() static void Main(string[] args) foreach (int i in c) foreach (int i in c.MaxToMin(1, 10)) foreach (int i in c.MinToMax) foreach (string s in c.GetDescriptions())
1.迭代抽象:访问一个聚合对象的内容而无需暴露它的内部表示。 2.迭代多态:为遍历不同的集合结构提供一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作。 3.迭代器的健壮性考虑:遍历的同时更改迭代器所在的集合结构,会导致问题。 适用性 1.访问一个聚合对象的内容而无需暴露它的内部表示。 2.支持对聚合对象的多种遍历。 3.为遍历不同的聚合结构提供一个统一的接口(即, 支持多态迭代)。 总结 Iterator模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明的访问集合内部的数据 |