IEnumerator和IEnumerable详解
IEnumerator和IEnumerable
从名字常来看,IEnumerator是枚举器的意思,IEnumerable是可枚举的意思。
了解了两个接口代表的含义后,接着看源码:
IEnumerator:
public interface IEnumerator
{
// Interfaces are not serializable
// Advances the enumerator to the next element of the enumeration and
// returns a boolean indicating whether an element is available. Upon
// creation, an enumerator is conceptually positioned before the first
// element of the enumeration, and the first call to MoveNext
// brings the first element of the enumeration into view.
//
bool MoveNext();
// Returns the current element of the enumeration. The returned value is
// undefined before the first call to MoveNext and following a
// call to MoveNext that returned false. Multiple calls to
// GetCurrent with no intervening calls to MoveNext
// will return the same object.
//
Object Current {
get;
}
// Resets the enumerator to the beginning of the enumeration, starting over.
// The preferred behavior for Reset is to return the exact same enumeration.
// This means if you modify the underlying collection then call Reset, your
// IEnumerator will be invalid, just as it would have been if you had called
// MoveNext or Current.
//
void Reset();
}
IEnumerable:
public interface IEnumerable
{
// Interfaces are not serializable
// Returns an IEnumerator for this enumerable Object. The enumerator provides
// a simple way to access all the contents of a collection.
[Pure]
[DispId(-4)]
IEnumerator GetEnumerator();
}
发现IEnumerable只有一个GetEnumerator函数,返回值是IEnumerator类型,从注释我们可以得知IEnumerable代表继承此接口的类可以获取一个IEnumerator来实现枚举这个类中包含的集合中的元素的功能(比如List<T>,ArrayList,Dictionary等继承了IEnumeratble接口的类)。
用foreach来了解IEnumerable,IEnumerator的工作原理
我们模仿ArrayList来实现一个简单的ConstArrayList,然后用foreach遍历。
//一个常量的数组,用于foreach遍历
class ConstArrayList : IEnumerable
{
public int[] constItems = new int[] { 1, 2, 3, 4, 5 };
public IEnumerator GetEnumerator()
{
return new ConstArrayListEnumeratorSimple(this);
}
}
//这个常量数组的迭代器
class ConstArrayListEnumeratorSimple : IEnumerator
{
ConstArrayList list;
int index;
int currentElement;
public ConstArrayListEnumeratorSimple(ConstArrayList _list)
{
list = _list;
index = -1;
}
public object Current
{
get
{
return currentElement;
}
}
public bool MoveNext()
{
if(index < list.constItems.Length - 1)
{
currentElement = list.constItems[++index];
return true;
}
else
{
currentElement = -1;
return false;
}
}
public void Reset()
{
index = -1;
}
}
class Program
{
static void Main(string[] args)
{
ConstArrayList constArrayList = new ConstArrayList();
foreach(int item in constArrayList)
{
WriteLine(item);
}
ReadKey();
}
}
输出结果:
1
2
3
4
5
代码达到了遍历效果,但是在用foreach遍历时,IEnumerator和IEnumerable究竟是如何运行的,我们可以通过增加增加日志可以直观的看到原因。
//一个常量的数组,用于foreach遍历
class ConstArrayList : IEnumerable
{
public int[] constItems = new int[] { 1, 2, 3, 4, 5 };
public IEnumerator GetEnumerator()
{
WriteLine("GetIEnumerator");
return new ConstArrayListEnumeratorSimple(this);
}
}
//这个常量数组的迭代器
class ConstArrayListEnumeratorSimple : IEnumerator
{
ConstArrayList list;
int index;
int currentElement;
public ConstArrayListEnumeratorSimple(ConstArrayList _list)
{
list = _list;
index = -1;
}
public object Current
{
get
{
WriteLine("Current");
return currentElement;
}
}
public bool MoveNext()
{
if(index < list.constItems.Length - 1)
{
WriteLine("MoveNext true");
currentElement = list.constItems[++index];
return true;
}
else
{
WriteLine("MoveNext false");
currentElement = -1;
return false;
}
}
public void Reset()
{
WriteLine("Reset");
index = -1;
}
}
class Program
{
static void Main(string[] args)
{
ConstArrayList constArrayList = new ConstArrayList();
foreach(int item in constArrayList)
{
WriteLine(item);
}
ReadKey();
}
}
输出结果:
GetIEnumerator
MoveNext true
Current
1
MoveNext true
Current
2
MoveNext true
Current
3
MoveNext true
Current
4
MoveNext true
Current
5
MoveNext false
通过输出结果,我们可以发现,foreach在运行时会先调用ConstArrayList的GetIEnumerator函数获取一个ConstArrayListEnumeratorSimple,之后通过循环调用ConstArrayListEnumeratorSimple的MoveNext函数,index后移,更新Current属性,然后返回Current属性,直到MoveNext返回false。
总结一下:
GetIEnumerator()负责获取枚举器。
MoveNext()负责让Current获取下一个值,并判断遍历是否结束。
Current负责返回当前指向的值。
Rest()负责重置枚举器的状态(在foreach中没有用到)
这些就是IEnumerable,IEnumerator的基本工作原理了。
其次我们发现:
ConstArrayList constArrayList = new ConstArrayList();
foreach(int item in constArrayList)
{
writeLine(item);
}
其实就等价于:
ConstArrayList constArrayList = new ConstArrayList();
IEnumerator enumeratorSimple = constArrayList.GetEnumerator();
while (enumeratorSimple.MoveNext())
{
int item = (int)enumeratorSimple.Current;
WriteLine(item);
}
也就是说foreach其实是一种语法糖,用来简化对可枚举元素的遍历代码。而被遍历的类通过实现IEnumerable接口和一个相关的IEnumerator枚举器来实现遍历功能。
IEnumerator和IEnumerable详解的更多相关文章
- IEnumerator:概念详解
IEnumerable接口是非常的简单,只包含一个抽象的方法GetEnumerator(),它返回一个可用于循环访问集合的IEnumerator对象.IEnumerator对象有什么呢?它是一个真正的 ...
- IEnumerable和IEnumerator 详解 分类: C# 2014-12-05 11:47 18人阅读 评论(0) 收藏
原:<div class="article_title"> <span class="ico ico_type_Original">&l ...
- IEnumerable<T> 接口和GetEnumerator 详解
IEnumerable<T> 接口 .NET Framework 4.6 and 4.5 公开枚举数,该枚举数支持在指定类型的集合上进行简单迭代. 若要浏览此类型的.NET Frame ...
- Git使用总结 Asp.net生命周期与Http协议 托管代码与非托管代码的区别 通过IEnumerable接口遍历数据 依赖注入与控制反转 C#多线程——优先级 AutoFac容器初步 C#特性详解 C#特性详解 WPF 可触摸移动的ScrollViewer控件 .NET(C#)能开发出什么样的APP?盘点那些通过Smobiler开发的移动应用
一,原理 首先,我们要明白Git是什么,它是一个管理工具或软件,用来管理什么的呢?当然是在软件开发过程中管理软件或者文件的不同版本的工具,一些作家也可以用这个管理自己创作的文本文件,由Linus开发的 ...
- C# IEnumerator的详解
迭代器模式是设计模式中行为模式(behavioral pattern)的一个例子,他是一种简化对象间通讯的模式,也是一种非常容易理解和使用的模式.简单来说,迭代器模式使得你能够获取到序列中的所有元素而 ...
- Linq之旅:Linq入门详解(Linq to Objects)
示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...
- C# LINQ详解(转)
C# LINQ详解(一) 原文标题:How does it work in C#?-Part 3 (C# LINQ in detail),作者:Mohammand A Rahman. 目录 LIN ...
- C# ~ 从 IEnumerable / IEnumerator 到 IEnumerable<T> / IEnumerator<T> 到 yield
IEnumerable / IEnumerator 首先,IEnumerable / IEnumerator 接口定义如下: public interface IEnumerable /// 可枚举接 ...
- Delphi TStringHelper用法详解
Delphi TStringHelper用法详解 (2013-08-27 22:45:42) 转载▼ 标签: delphi_xe5 it 分类: Delphi Delphi XE4的TStringHe ...
随机推荐
- Dive查看docker镜像层信息
1.主要采用docker运行dive的方式,不然宿主机还要安装go那些挺麻烦的.具体用法可查看官方: https://github.com/wagoodman/dive 2.拉取dive镜像 dock ...
- 2014.9.11 Research Meeting Report
Dear All: Yesterday when we read INFOCOM papers, you have seen how damage it is to have careless wri ...
- Unity导入模型出现 (Avatar Rig Configuration mis-match. Bone length in configuration does not match position in animation)?
昨天遇到这两个模型导入的问题,查了一下资料,自己摸索了一下解决方法..总结一下~ 出现的原因:(问题1)Warning 当模型文件导入以后并且设置Animation Type是Generic的时候,动 ...
- 条件GAN论文简单解读
条件GAN(Conditional Generative Adversarial Nets),原文地址为CGAN. Abstract 生成对抗网络(GAN)是最近提出的训练生成模型(g ...
- PHP完美分页类
<?php /** file: page.class.php 完美分页类 Page */ class Page { private $total; //数据表中总记录数 private $lis ...
- 浅介MVC与Backbone
1.MVC是什么东西? MVC (Modal View Controler) 是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器(Controll ...
- Backbone实践案例
By:软件11 王思伦 2013-10-4 Backbone简述: Backbone基于MVC架构,用于开发重量级Javascript应用的框架. 如上文所述,Backbone包含多种类,但主要包含了 ...
- 第一次Spring会议成果意见汇总
第一组:9-625 只看到了界面,而两台笔记本电脑通过局域网进行通信的功能则没有看到,没有看到实质性的成果.他们的软件还是非常实用的,它仅通过局域网就能通信,大大减少了流量费用,提高了通信效率,希望 ...
- 记初学net-SNMP
自从弄完那个jsp的网盘(其实还是个烂摊子),这几天一直在研究snmp. 有需求就激发动力,对,人都是被逼出来的.五一这几天,天天搁这坐着,毫无头绪. 下面切入正题. 要做一个监控园区网在线数的平台, ...
- 关于Python matplotlib显示汉字乱码问题
我也是一个初学者,在今天编程时遇到的一个问题,我是基于Eclipse编写Python代码,在使用matplotlib进行数据可视化时,发现显示不了汉字并且出现乱码问题. (1)使用中文注释时报错: 解 ...