一、前言

假设存在一个数组,其遍历模式是根据索引进行遍历的;又假设存在一个HashTable,其遍历模式是根据键值进行遍历的;无论哪种集合,如果它们的遍历没有一个共同的接口,那么在客户端进行调用的时候,就需要对每种集合的具体类型进行它们各自的具体代码编写,当需求发生变化时,就必须修改我们的代码。并且客户端过多的关注集合内部的实现,代码的移植性就会变差,违反了开闭原则,这个时候迭代器就诞生了,现在我们来根据上一章 foreach遍历原理(一)实现我们自己的迭代器。

二、代码示例

 class Program
    {
        static void Main(string[] args)
        {
            //使用接口IMyEnumerable代替MyList
            IMyEnumerable list = new MyList();
            //得到迭代器,在循环中针对迭代器编码,而不是集合MyList
            IMyEnumerator enumerator = list.GetEnumerator();

            while (enumerator.MoveNext())
            {
                object current = enumerator.Current;
                Console.WriteLine(current);
            }
            Console.ReadKey();
        }

        /// <summary>
        /// 要求所有的迭代器全部实现该接口
        /// </summary>
        interface IMyEnumerator
        {
            bool MoveNext();
            object Current { get; }
        }

        /// <summary>
        /// 要求所有的集合实现该接口
        /// 这样一来,客户端就可以针对该接口编码,
        /// 而无须关注具体的实现
        /// </summary>
        interface IMyEnumerable
        {
            IMyEnumerator GetEnumerator();
            int Count { get; }
        }

        class MyList : IMyEnumerable
        {
            ]{,,,,,,,,,};
            IMyEnumerator myEnumerator;

            public object this[int i]
            {
                get { return items[i]; }
                set { this.items[i] = value; }
            }

            public int Count
            {
                get { return items.Length; }
            }

            public IMyEnumerator GetEnumerator()
            {
                if (myEnumerator == null)
                {
                    myEnumerator = new MyEnumerator(this);
                }
                return myEnumerator;
            }
        }

        class MyEnumerator : IMyEnumerator
        {
            ;
            MyList myList;
            public MyEnumerator(MyList myList)
            {
                this.myList = myList;
            }

            public bool MoveNext()
            {
                 > myList.Count)
                {
                    index = ;
                    return false;
                }
                else
                {
                    index++;
                    return true;
                }
            }

            public object Current
            {
                ]; }
            }
        }

    }

运行结果:

三、疑问——为什么不把 IMyEnumerable 和 IMyEnumerator 接口写在同一个接口里面,例如新建一个接口名字为 IForeach,不使用迭代器,也能输出上面的结果

  class Program
    {
        static void Main(string[] args)
        {
            IForeach iForeach = new MyList();
            while (iForeach.MoveNext())
            {
                object current = iForeach.Current;
                Console.WriteLine(current);
            }
            Console.ReadKey();
        }

        interface IForeach
        {
            bool MoveNext();
            object Current { get; }
            int Count { get; }
        }

        class MyList : IForeach
        {
            ] { , , , , , , , , ,  };
            ;

            public object this[int i]
            {
                get { return items[i]; }
                set { this.items[i] = value; }
            }

            public int Count
            {
                get { return items.Length; }
            }

            public bool MoveNext()
            {
                 > Count)
                {
                    index = ;
                    return false;
                }
                else
                {
                    index++;
                    return true;
                }
            }

            public object Current
            {
                ]; }
            }
        }
    }

四、如果我现在有新需求要倒序输出,那么按照上面“三”的做法,就必须修改 MyList  类里面的代码,而且是大改。如果使用迭代器 ,我们只需要重新写类继承迭代器IMyEnumerator,替换一下迭代器,就能够实现MyList  的倒序输出。

新增一个倒序迭代器

 class MyInvertEnumerator : IMyEnumerator
        {
            ;
            MyList myList;
            public MyInvertEnumerator(MyList myList)
            {
                this.myList = myList;
                index = myList.Count;
            }

            public bool MoveNext()
            {
                 <)
                {
                    index = myList.Count;
                    return false;
                }
                else
                {
                    index--;
                    return true;
                }
            }

            public object Current
            {
                get { return myList[index]; }
            }
        }

修改MyList集合里面获取迭代器的方法,然后运行就能够

   class MyList : IMyEnumerable
        {
            ]{,,,,,,,,,};
            IMyEnumerator myEnumerator;

            public object this[int i]
            {
                get { return items[i]; }
                set { this.items[i] = value; }
            }

            public int Count
            {
                get { return items.Length; }
            }

            public IMyEnumerator GetEnumerator()
            {
                if (myEnumerator == null)
                {
                  //  myEnumerator = new MyEnumerator(this);//正序输出
                    myEnumerator = new MyInvertEnumerator(this);//倒序输出
                }
                return myEnumerator;
            }
        }

倒序输出完整代码:

 class Program
    {
        static void Main(string[] args)
        {
            //使用接口IMyEnumerable代替MyList
            IMyEnumerable list = new MyList();
            //得到迭代器,在循环中针对迭代器编码,而不是集合MyList
            IMyEnumerator enumerator = list.GetEnumerator();

            while (enumerator.MoveNext())
            {
                object current = enumerator.Current;
                Console.WriteLine(current);
            }
            Console.ReadKey();
        }

        /// <summary>
        /// 要求所有的迭代器全部实现该接口
        /// </summary>
        interface IMyEnumerator
        {
            bool MoveNext();
            object Current { get; }
        }

        /// <summary>
        /// 要求所有的集合实现该接口
        /// 这样一来,客户端就可以针对该接口编码,
        /// 而无须关注具体的实现
        /// </summary>
        interface IMyEnumerable
        {
            IMyEnumerator GetEnumerator();
            int Count { get; }
        }

        class MyList : IMyEnumerable
        {
            ]{,,,,,,,,,};
            IMyEnumerator myEnumerator;

            public object this[int i]
            {
                get { return items[i]; }
                set { this.items[i] = value; }
            }

            public int Count
            {
                get { return items.Length; }
            }

            public IMyEnumerator GetEnumerator()
            {
                if (myEnumerator == null)
                {
                  //  myEnumerator = new MyEnumerator(this);//正序输出
                    myEnumerator = new MyInvertEnumerator(this);//倒序输出
                }
                return myEnumerator;
            }
        }

        class MyEnumerator : IMyEnumerator
        {
            ;
            MyList myList;
            public MyEnumerator(MyList myList)
            {
                this.myList = myList;
            }

            public bool MoveNext()
            {
                 > myList.Count)
                {
                    index = ;
                    return false;
                }
                else
                {
                    index++;
                    return true;
                }
            }

            public object Current
            {
                ]; }
            }
        }

        class MyInvertEnumerator : IMyEnumerator
        {
            ;
            MyList myList;
            public MyInvertEnumerator(MyList myList)
            {
                this.myList = myList;
                index = myList.Count;
            }

            public bool MoveNext()
            {
                 <)
                {
                    index = myList.Count;
                    return false;
                }
                else
                {
                    index--;
                    return true;
                }
            }

            public object Current
            {
                get { return myList[index]; }
            }
        }

    }

迭代器就讲到这里了,谢谢大家。

foreach遍历扩展(二)的更多相关文章

  1. c#--foreach遍历的用法与split的用法

    一. foreach循环用于列举出集合中所有的元素,foreach语句中的表达式由关键字in隔开的两个项组成.in右边的项是集合名,in左边的项是变量名,用来存放该集合中的每个元素.      该循环 ...

  2. 用数组指针遍历数组,FOR/FOREACH遍历数组

    1. 用数组指针遍历一维数组 <?php header("Content-type:text/html;charset=utf-8"); /*用数组指针遍历一位数组的值*/ ...

  3. foreach遍历数组

    foreach遍历一维数组 <?php //PHP数组遍历:foreach //定义数组 $arr=array(1,2,3,4,5,6,7,8,9,10); //foreach循环 foreac ...

  4. C# 表达式树遍历(二)

    一.前言 上一篇我们对表达式树有了初步的认识,这里我们将对表达式树进行遍历,只有弄清楚了他的运行原理,我们才可以对他进行定制化修改. 表达式系列目录 C# 表达式树讲解(一) C# 表达式树遍历(二) ...

  5. C#实现在foreach遍历中删除集合中的元素(方法总结)

    目录 方法一:采用for循环,并且从尾到头遍历 方法二:使用递归 方法三:通过泛型类实现IEnumerator 在foreach中删除元素时,每一次删除都会导致集合的大小和元素索引值发生变化,从而导致 ...

  6. 关于for与forEach遍历集合中对集合进行操作的问题

    遍历List集合,在循环中再对List集合进行操作,有时候会遇到ConcurrentModificationException(并发修改异常);其实只有在forEach循环集合再对集合操作会发生异常: ...

  7. 用<forEach>遍历list集合时,提示我找不到对象的属性

    <c:forEach items="${list}" var="item"> <tr> <td>${item.UserId} ...

  8. Foreach遍历

    前天在项目中遇到一个问题,foreach遍历过程中修改responses中的对象,其中responses的类型:IEnumerable<Order>,代码如下: foreach (Orde ...

  9. 使用yield关键字让自定义集合实现foreach遍历

    一般来说当我们创建自定义集合的时候为了让其能支持foreach遍历,就只能让其实现IEnumerable接口(可能还要实现IEnumerator接口) 但是我们也可以通过使用yield关键字构建的迭代 ...

随机推荐

  1. js中运算符的优先级

    不确定下面表达式的运算顺序? a>b?c:d+e a&&b==c 看看下表就清楚了,下表按优先级从最高到最低的列出,具有相同优先级按从左至右的顺序求值. 运算符 描述 . [] ...

  2. ASP.NET常用技术之Cookie

    cookie是一小段的文本信息(多数浏览器限制cookie最大字节数为4096字节),在浏览器和服务器之间随用户请求而传递(用户访问网站,没有设置cookie限制范围情况下,无论请求那个页面,浏览器和 ...

  3. 使用 phpMyAdmin无法登录mysql的问题

    今天使用使用phpmyadmin时出现了以下错误: (1)第一次时: 当配置文件config.inc.php里的配置项是: $cfg['Servers'][$i]['host'] = 'localho ...

  4. PHP自定义弹出消息类,用于弹出提示信息并返回

    一个用PHP自写的弹出消息类,用于在程序出错时弹出提示,,弹出警告框,或在程序运行到某阶段的快捷提示,需用时只需传入参数即可,函数并不复杂,但觉得挺实用.具体代码: function Alert($a ...

  5. 比file_get_contents稳定的curl_get_contents

    相信使用过file_get_contents函数的朋友都知道,当获取的$url访问不了时,会导致页面漫长的等待,甚至还能导致PHP进程占用CPU达100%,因此这个函数就诞生了 分享一个实际在用的函数 ...

  6. 如何使用service命令来管理nginx

    如何使用service命令来管理nginx??? 如: service nginx start service nginx restart service nginx stop service ngi ...

  7. 【学习笔记】【oc】copy与mutableCopy

    copy 返回一个不可变的对象: mutableCopy 返回一个可变的对象: 使用copy方法时 类必须实现:<NSCopying>协议中的-(id)copyWithZone:(NSZo ...

  8. Docker容器环境下ASP.NET Core Web API

    Docker容器环境下ASP.NET Core Web API应用程序的调试 本文主要介绍通过Visual Studio 2015 Tools for Docker – Preview插件,在Dock ...

  9. web安全:click jacking

    点击劫持  click jacking通过iframe加载被攻击网站到黑客自己维护的网站通过z-index叠加和position定位,将2个网站的信息堆叠在一个立体投影面上,通过opacity设置透明 ...

  10. 一个正整数N,拆成任意个正整数之和,怎样使这些数的乘积最大

    网上看到了如标题所示的题目,就开始想如果用程序来算的话,那么它的算法是怎样的. 自己想了半天,第一感觉要用递归, 如先算出 当 n=1 max=1 当 n=2 max=1 当 n=3 max=2 .. ...