foreach遍历扩展(二)
一、前言
假设存在一个数组,其遍历模式是根据索引进行遍历的;又假设存在一个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遍历扩展(二)的更多相关文章
- c#--foreach遍历的用法与split的用法
一. foreach循环用于列举出集合中所有的元素,foreach语句中的表达式由关键字in隔开的两个项组成.in右边的项是集合名,in左边的项是变量名,用来存放该集合中的每个元素. 该循环 ...
- 用数组指针遍历数组,FOR/FOREACH遍历数组
1. 用数组指针遍历一维数组 <?php header("Content-type:text/html;charset=utf-8"); /*用数组指针遍历一位数组的值*/ ...
- foreach遍历数组
foreach遍历一维数组 <?php //PHP数组遍历:foreach //定义数组 $arr=array(1,2,3,4,5,6,7,8,9,10); //foreach循环 foreac ...
- C# 表达式树遍历(二)
一.前言 上一篇我们对表达式树有了初步的认识,这里我们将对表达式树进行遍历,只有弄清楚了他的运行原理,我们才可以对他进行定制化修改. 表达式系列目录 C# 表达式树讲解(一) C# 表达式树遍历(二) ...
- C#实现在foreach遍历中删除集合中的元素(方法总结)
目录 方法一:采用for循环,并且从尾到头遍历 方法二:使用递归 方法三:通过泛型类实现IEnumerator 在foreach中删除元素时,每一次删除都会导致集合的大小和元素索引值发生变化,从而导致 ...
- 关于for与forEach遍历集合中对集合进行操作的问题
遍历List集合,在循环中再对List集合进行操作,有时候会遇到ConcurrentModificationException(并发修改异常);其实只有在forEach循环集合再对集合操作会发生异常: ...
- 用<forEach>遍历list集合时,提示我找不到对象的属性
<c:forEach items="${list}" var="item"> <tr> <td>${item.UserId} ...
- Foreach遍历
前天在项目中遇到一个问题,foreach遍历过程中修改responses中的对象,其中responses的类型:IEnumerable<Order>,代码如下: foreach (Orde ...
- 使用yield关键字让自定义集合实现foreach遍历
一般来说当我们创建自定义集合的时候为了让其能支持foreach遍历,就只能让其实现IEnumerable接口(可能还要实现IEnumerator接口) 但是我们也可以通过使用yield关键字构建的迭代 ...
随机推荐
- javascript 不用ajax 用 iframe 子域名下做到ajax post数据
最近在一个项目中遇到了ajax跨域的问题,情况如下.有三个域名分别是 a.xx.com b.xx.com c.xx.com 这三个域名都会用用ajax post方式相互读取数据.文笔不好, 不写了妈蛋 ...
- Python自动化运维之8、正则表达式re模块
re模块 正则表达式使用单个字符串来描述.匹配一系列符合某个句法规则的字符串,在文本处理方面功能非常强大,也经常用作爬虫,来爬取特定内容,Python本身不支持正则,但是通过导入re模块,Python ...
- 04 - 替换vtkDataObject中的GetPipelineInformation 和GetExecutive 方法 VTK 6.0 迁移
VTK6 引入了许多不兼容的变.其中之一是删除vtkDataObject中所有有关管道的方法.其中的两个方法就是GetPipelineInformation() 和 GetExecutive().这些 ...
- 关于nginx架构探究(4)
事件管理机制 Nginx是以事件驱动的,也就是说Nginx内部流程的向前推进基本都是靠各种事件的触发来驱动,否则Nginx将一直阻塞在函数epoll_wait()或suspend函数,Nginx事件一 ...
- 转:exit()与_exit()的区别
版权声明:本文为博主原创文章,未经博主允许不得转载. 从图中可以看出,_exit 函数的作用是:直接使进程停止运行,清除其使用的内存空间,并清除其在内核的各种数据结构:exit 函数则在这些基础上做了 ...
- 用MySQL创建数据库和数据库表
1.使用SHOW语句找出在服务器上当前存在什么数据库: mysql> SHOW DATABASES; +----------+ | Database | +----------+ | mysql ...
- 【网贷投资手册】P2P行业揭秘
[网贷投资手册]P2P行业揭秘 (中国电子商务研究中心讯)如果你手头有100元,你会拿它来做什么?跟好朋友去吃一顿?跟女朋友去看场电影?还是……你会想到拿100元去投资吗?100元太少了,买一 ...
- DELPHI7如何调用带参数的JAVA WebService
对方提供的WebService地址是http://192.168.1.6:8080/test/pic?XH=XX用DELPHI如何调呢 ------解决方案--------------------通过 ...
- Android取得电池的电量
首先需要用到的是一个类继承BrocastReceiver 2 代码如下: public class Battery_Info extends BroadcastReceiver { @Override ...
- 在 SQL Server 2012 附加 Adventure Works 範例資料庫
原文地址:http://technet.microsoft.com/zh-tw/library/eb1f9417-4cca-4575-a725-187bcd60c7e7 附加数据库时报错 错误5123 ...