迭代器

迭代器概述

迭代器是可以返回相同类型的值的有序序列的一段代码。迭代器可用作方法、运算符或 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
    {
        string[] _days = { "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" };

        public System.Collections.IEnumerator GetEnumerator()
        {
            for (int i = 0; i < _days.Length; i++)
            {
                yield return _days[i];
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            DaysOfTheWeek week = new DaysOfTheWeek();
            foreach (string day in week)
            {
                Console.WriteLine(day);
            }
            Console.Read();
        }
    }

 

操作结果是:

Sun Mon Tue Wed Thr Fri Sat

其中yied return关键字产生枚举元素

泛型版迭代器的实现代码如下:

    public class Stack<T> : IEnumerable<T>
    {
        public T[] items;

        public IEnumerator<T> GetEnumerator()
        {
            for (int i = 0; i < items.Length; i++)
            {
                yield return items[i];
            }
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

    class Program1
    {
        static void Main(string[] args)
        {
            Stack<int> stack = new Stack<int>();
            stack.items = new int[] { 1, 2, 3, 4, 5, 6 };

            foreach (int item in stack)
            {
                Console.WriteLine(item);
            }
            Console.Read();
        }
    }

 

在自定义迭代器时,我们可以利用yield break关键字跳出循环。如上面的例子中,我们想只输出小于等于5的项,调整上面代码,如:

  public class Stack<T> : IEnumerable<T>    
  {    
    public T[] items;     
   
    public IEnumerator<T> GetEnumerator()    
    {    
   
      for (int i = 0; i < items.Length; i++)    
      {            
   
        if ((Convert.ToInt32(items[i]) > 5))    
          yield break;    
   
        yield return items[i];    
      }    
    }     
   
    IEnumerator IEnumerable.GetEnumerator()    
    {    
      return GetEnumerator();    
    }    
  }    

 

迭代器的机制:

实际上迭代器只是在C#2.0中通过编译器一层额外处理的,用来简化创建可用于foreach的枚举集合的工作,从性能上没有什么变化。对于其生成的中间语言没有太多的变化。


实例:定义和使用命名迭代器

    public class Class1<T> : IEnumerable<T>
    {
        public T[] value;

        public IEnumerator<T> GetEnumerator()
        {
            for (int i = 0; i < value.Length; i++)
            {
                yield return value[i];
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        // 定义一个命名的迭代器,并可以提供参数    
        public IEnumerable<T> MaxToMin(int min, int max)
        {
            for (int i = max; i >= min; i--)
            {
                yield return value[i];
            }
        }

        // 定义一个迭代器类型的属性,    
        public IEnumerable<T> MinToMax
        {
            // this表示该类实例,因为该类实现了GetEnumerator(),它是可枚举的    
            get { return this; }
        }

        public IEnumerable GetDescriptions()
        {
            yield return "this is my test";
            yield return "class name is class1";
            yield return "ktgu";
        }

    }

    class Program1
    {
        static void Main(string[] args)
        {

            Class1<int> c = new Class1<int>();
            c.value = new int[] { 1, 2, 3, 4, 5, 6 };
            foreach (int i in c)
          {
                Console.WriteLine(i);
            }

            foreach (int i in c.MaxToMin(1, 5))
            {
                Console.WriteLine(i);
            }

            foreach (int i in c.MinToMax)
            {
                Console.WriteLine(i);
            }

            foreach (string s in c.GetDescriptions())
            {
                Console.WriteLine(s);
            }

            Console.Read();
        }

迭代效果及实现要点

1.迭代抽象:访问一个聚合对象的内容而无需暴露它的内部表示。

2.迭代多态:为遍历不同的集合结构提供一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作。

3.迭代器的健壮性考虑:遍历的同时更改迭代器所在的集合结构,会导致问题。 

适用性

1.访问一个聚合对象的内容而无需暴露它的内部表示。

2.支持对聚合对象的多种遍历。

3.为遍历不同的聚合结构提供一个统一的接口(即, 支持多态迭代)。 

总结

Iterator模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明的访问集合内部的数据

posted @ 2010-09-14 17:42  英雄不问出处  阅读(244)  评论(0编辑  收藏  举报