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关键字构建的迭代 ...
随机推荐
- Oracle数据库之数据类型
Oracle数据库之数据类型 Oracle基本数据类型(亦叫内置数据类型,internal datatypes或built-in datatypes)可以按类型分为:字符串类型.数字类型.日期类型.L ...
- WDCP安装memcached
memcached安装 我们打开Web控制面板的时候其实memcached是没有安装的,所以我们要手动安装这个组件. 首先是要下载安装源代码并执行. 1 2 wget -c http://down.w ...
- python 多层装饰器
25.多层装饰器: 1.原理:执行顺序从上往下,#2和#3组成一个函数假设为nf1,#1和nf1组成一个函数nnf1 f1成为ck_ty_of_us的inner函数即nf ...
- C#7.0
C#7.0中有哪些新特性? 以下将是 C# 7.0 中所有计划的语言特性的描述.随着 Visual Studio “15” Preview 4 版本的发布,这些特性中的大部分将活跃起来.现在是时候来展 ...
- DotNET知识点总结五(笔记整合)
1.委托:通常指的是 多播委托 通常的说,委托就是一个存放方法指针的容器,是一个安全的函数指针,供程序员安全调用.委托的本质就是一个类,继承于MulticastDelegate——>Delega ...
- android 安卓 微信布局 [1]
微信布局 直接上代码吧 ---------------------------------------- 头部 -------------------------------------------- ...
- IE6/IE7不识别display:inline-block属性怎么办
ie6,ie7的haslayout属性是个让人头疼的问题.在做导航条的时候,一般会用到ul li结构,大多数时候我们是把li设置为浮动,让其并排显示在同一行.还有一种方法就是设置li为display: ...
- Java DES 测试
package com.des.test; import java.io.UnsupportedEncodingException; import java.security.InvalidKeyEx ...
- Linux服务器间信任关系建立方法
http://blog.csdn.net/jiangzeyun/article/details/42489359
- 用PYTHON实现将电脑里的所有文件按大小排序,便于清理
嘿嘿,慢慢找到写代码的感觉了. 这个小程序涉及的东东还是很多的,数据结构的设计,错误的处理,快速字典排序,文件数值调整.... import os,os.path import glob SUFFIX ...