/*自定义导航栏*/

【c#迭代器】

在.NET中,迭代器模式被IEnumerator和IEnumerable及其对应的泛型接口所封装。如果一个类实现了IEnumerable接口,那么就能够被迭代;调用GetEnumerator方法将返回IEnumerator接口的实现,它就是迭代器本身。迭代器类似数据库中的游标,他是数据序列中的一个位置记录。迭代器只能向前移动,同一数据序列中可以有多个迭代器同时对数据进行操作。

以一个手动迭代器为例子,进行详解迭代器:假如我们有一个集合添加“我,爱,的,是,c#”五个字母,那么输出时想从第三个开始输出,结果既是“是,c#,我,爱,的”,该怎么实现?迭代器就登场了......

        /// <summary>
        /// 主题:C#扫盲之迭代器
        /// 时间:2013-1-4 20:33:50
        /// 描述:利用迭代器输出字符串,从自己编写到优化
        /// 作者:白宁超
        /// </summary>
        /// <param name="args"></param>

Sample类的迭代及创建如下:

  /// <summary>
    /// 主题:类的迭代输出初始化字符串
    /// 时间:2013-1-4 20:40:15
    /// 描述:通过创建Sample,实现字符串从第三个数打印出
    /// 作者:白宁超
    /// </summary>
     class Sample:IEnumerable
    {
        public  Object[] values;               //定义对象作为集合参数
        public  int starting;           //定义迭代起始点
        public Sample(Object[] values, Int32 starting) //构造方法
        {
            this.values = values;
            this.starting = starting;
        }
        // 摘要:返回一个循环访问集合的枚举器。
        // 返回结果:可用于循环访问集合的 System.Collections.IEnumerator 对象。
        public IEnumerator GetEnumerator()      
        {
            return new IterationSample(this);
        }
    }

 IterationSample迭代如下:为Sample类GetEnumerator方法提供返回值

/// <summary>
     /// 主题:构造类的返回值
    /// 时间:2013-1-4 20:41:49
     /// 描述: IterationSample类来实现迭代器本身,通过GetEnumerator方法返回集合值
    /// 作者:白宁超
    /// </summary>
    class IterationSample : IEnumerator
    {
        Sample parent;//迭代的对象  
        int position;//当前游标的位置 
        internal IterationSample(Sample parent)
        {
            this.parent = parent;
            position = -1;// 数组元素下标从0开始,初始时默认当前游标设置为 -1,即在第一个元素之前, 
        }
        //获取集合中的当前元素
        public object Current
        {
            get
            {
                if (position == -1 || position == parent.values.Length)//第一个之前和最后一个自后的访问非法 
                {
                    throw new InvalidOperationException();
                }
                int index = position + parent.starting;//考虑自定义开始位置的情况  
                index = index % parent.values.Length;
                return parent.values[index];
            }
        }
        //将枚举数推进到集合的下一个元素
        public bool MoveNext()
        {
            if (position != parent.values.Length) //判断当前位置是否为最后一个,如果不是游标自增 
            {
                position++;
            }
            return position < parent.values.Length;
        }
        //将枚举数设置为其初始位置,该位置位于集合中第一个元素之前。
        public void Reset()
        {
            position = -1;//将游标重置为-1  
        }
    }
 /// <summary>
        /// 主题:C#扫盲之迭代器
        /// 时间:2013-1-4 20:33:50
        /// 描述:利用迭代器输出字符串,从自己编写到优化
        /// 作者:白宁超
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            //简单迭代器操作
            object[] values = { "我", "爱", "的", "是", "C#" };//初始化数组“我爱的是C#”
            Sample collection = new Sample(values, 3);         //Sample类实例化
            foreach (object x in collection)                    //循环打印
            {
                Console.WriteLine(x);
            }
            Console.ReadKey();
        }

 以上是手写迭代器,还有一个更简便的方法,可以省去IterationSample类的迭代,即只需要Sample类GetEnumerator方法添加for循环语句,利用yield ruturn便可得到我们所希望的结果:

        // 摘要:返回一个循环访问集合的枚举器。
        // 返回结果:可用于循环访问集合的 System.Collections.IEnumerator 对象。
        public IEnumerator GetEnumerator()      
        {
            //return new IterationSample(this);
            //此方法减少代码量,是代码更优雅
            for (int index = 0; index < this.values.Length; index++)
            {
                yield return values[(index + starting) % values.Length];
            }
        }

IEnumerable<T>在LINQ中最重要的一个接口,如果想要在LINQ To Object上实现自己的LINQ操作,就会觉得迭代的方便性。值得注意的是,yield return语句停止了方法的执行,而不是退出方法,要想退出需要yield break,这根普通方法中的return一样。 

posted @ 2013-01-04 21:00  伏草惟存  阅读(365)  评论(0编辑  收藏  举报