C#设计模式(15)——迭代器模式

出处:https://www.cnblogs.com/wyy1234/

C#设计模式(15)——迭代器模式

 

1.迭代器模式介绍

  迭代器模式主要用于遍历聚合对象,将聚合对象的遍历行为分离出来,抽象为一个迭代器来负责。迭代器模式用的十分普遍,C#/JAVA等高级语言都对迭代器进行了封装用于遍历数组,集合,列表等,因为各种高级语言都对这种模式做了很好的封装,所以这种模式的使用价值远大于它的学习价值,MartinFlower甚至在网站上提出过撤销这个设计模式,所以这里不打算介绍迭代器模式的概念和原理,而是介绍C#中的迭代器模式应用:C#中的枚举器和迭代器。

2、枚举器和可枚举类型

先看一个简单的例子:

复制代码
1     static void Main(string[] args)
2         {
3             int[] arr = { 2,3,5,8};
4             foreach (int item in arr)
5             {
6                 Console.WriteLine("item's Value is :{0}",item);
7             }
8             Console.ReadKey();
9         }
复制代码

  为什么数组能够通过foreach遍历呢?原因是数组实现了IEnumerable接口,IEumerable接口中只有一个成员方法:GetEnumerator(),这个方法返回一个枚举器对象,这个枚举器就是迭代器模式中的迭代器。枚举器可以依次返回请求中数组中的元素,它知道元素的顺序并跟踪元素在序列中的位置,然后返回请求的当前项,我们可以通过GetEnumerator方法获取枚举器对象。那么什么是枚举器呢?实现IEnumerator接口的类型就是枚举器,该接口有三个成员:

   current :获取当前位置元素

   MoveNext() :把枚举器位置前进到下一项,返回bool,表示位置是否有效(如果没有下一项返回false)

   Reset() :把位置重置为原始状态的位置(有索引是一般为-1)

我们重新实现上边例子的foreach操作:

复制代码
 1      static void Main(string[] args)
 2         {
 3             int[] arr = { 2,3,5,8};
 4             //获取arr的枚举器
 5             IEnumerator ie = arr.GetEnumerator();
 6             while (ie.MoveNext())
 7             {
 8                 int i = (int)ie.Current;
 9                 Console.WriteLine("item's value is:{0}",i);
10             }
11             Console.ReadKey();
12         }
复制代码

  知道了foreach内部是怎么运行的后,我们就可以自己实现一个可以用foreach遍历的类了:自定义的类要实现IEnumerable接口的GetEnumerator方法,这个方法返回一个枚举器(就是一个继承IEnumerator接口的类型),以遍历自定义颜色集合为例,代码如下:

复制代码
   class Program
    {
        static void Main(string[] args)
        {
            ColorList colors = new ColorList();
            //foreach遍历自定义的类型
            foreach (var item in colors)
            {
                Console.WriteLine(item);
            }

            Console.ReadKey();

        }
        
        /// <summary>
        /// 自定义类 ColorList实现IEnumerable接口
        /// </summary>
        public class ColorList : IEnumerable
        {
            //实现GetEnumerator接口方法
            public IEnumerator GetEnumerator()
            {
                return new ColorEnumrator(new string[]{ "red", "blue", "green", "pink" });
            }
        }
        /// <summary>
        /// 自定义枚举器
        /// </summary>
        public class ColorEnumrator : IEnumerator
        {
            string[] _colors;
            //位置索引
            private int _position = -1;
            //枚举器构造方法
            public ColorEnumrator(string[] theColors)
            {
                _colors = new string[theColors.Length];
                for (int i = 0; i < theColors.Length; i++)
                {
                    _colors[i] = theColors[i];
                }
            }
            //获取当前项的值
            public object Current
            {
                get
                {
                    if (_position < 0 || _position > _colors.Length)
                    {
                        throw new Exception("超过边界了!");
                    }
                    return _colors[_position];
                }
            }
            //指向下一项
            public bool MoveNext()
            {
                if (_position<_colors.Length-1)
                {
                    _position++;
                    return true;
                }
                return false;
            }
            //复位
            public void Reset()
            {
                _position = -1;
            }
        }
    }
复制代码

程序运行结果如下:

总结:可枚举类型是实现了IEnumerable接口的类,IEnumerable接口只有一个成员GetEnumerator方法,用于获取枚举器(实现IEnumerator接口的实例)。

3.迭代器

  通过手动实现IEnumerable接口的IEnumerator方法我们已经可以实现自定义可枚举类型了,在C#2.0中提供了更简单的创建可枚举类型的方式:迭代器。我们使用迭代器时,不用我们自己去手动创建IEnumerator实例,编译器会自动帮我们生成IEnumerator内部的Current,MoveNext和Reset方法。使用迭代器上边的例子可以简化为:

复制代码
    class Program
    {
        static void Main(string[] args)
        {
            ColorList colors = new ColorList();
            //foreach遍历自定义的ColorList类型
            foreach (var item in colors)
            {
                Console.WriteLine(item);
            }
            Console.ReadKey();

           
        }
      
    }
    
    /// <summary>
    /// 自定义颜色集合,实现IEnumerable接口
    /// </summary>
    public class ColorList : IEnumerable
    {
        //实现GetEnumerator接口方法
        public IEnumerator GetEnumerator()
        {
            string[] colors= { "red", "green", "blue", "pink" };
            for (int i = 0; i < colors.Length; i++)
            {
                //yield return的作用是指定下一项的内容
                yield return colors[i];
            }

            //想反向遍历时可以这样写
            //for (int i = colors.Length-1; i >=0; i--)
            //{
            //    yield return colors[i];
            //}
        }
    }
复制代码

  程序运行结果和手动写Enumerator的例子一致,我们可以看出使用迭代器来生成可枚举类型要简单很多,这并不是创建迭代器的过程简单了,而是微软让编译器帮我们自动生成了IEnumerator中的current,MoveNext(),Reset()等内容。

原文地址:https://www.cnblogs.com/frank0812/p/11281549.html