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 ...
随机推荐
- iOSApp上下有黑边
如图: 这种情况就是没有启动页导致的,加了启动页图片之后就不会再出现了. 设置启动页的方法: http://www.cnblogs.com/BK-12345/p/5218229.html 有的人说我加 ...
- IDEA2018.1安装配置文档
一.软件安装 1. 下载地址: https://www.jetbrains.com/idea/download/#section=windows 2. 安装: 点击.exe,选择安装路径,点击next ...
- mui框架(三)
1.Ajax-get请求 // get测试请求地址 http://test.dongyixueyuan.com/link_app/get?state=index&num=0 mui.get(' ...
- Call actvity after viewpager is finished
private OnPageChangeListener mListener = new OnPageChangeListener() { @Override public void onPageSe ...
- 20135337朱荟潼 Linux第八周学习总结——进程的切换和系统的一般执行过程
第八周 进程的切换和系统的一般执行过程 一.进程切换关键代码switch_to 1.不同类型进程有不同调度需求--两种分类 2.调度策略--规则 Linux中进程优先级是动态的,周期性调整. 3.时机 ...
- 四则运算app总结
程序有难度和单项练习,但设计了每次只出5到题,如果做错的话会把错题加入到数据库中,然后通多错题巩固选项可以对错题进行训练. 代码: 普通选项代码: package com.example.szys; ...
- 第二个spring冲刺第3天
今天天气突然变得很冷,所以我们队的人都有少许的不适.加上天气比较冷,我们都不怎么想做.幸好在队长的提醒下,我们终于继续投入研发的工作中.由于市面上的同类软件的数量不少所以我们下载了一些来看,希望能找到 ...
- Alpha冲刺——day3
Alpha冲刺--day3 作业链接 Alpha冲刺随笔集 github地址 团队成员 031602636 许舒玲(队长) 031602237 吴杰婷 031602220 雷博浩 031602634 ...
- JetBrains系列WebStorm等中文输入法无法跟随光标的问题的解决办法
参考:https://blog.csdn.net/wang414300980/article/details/79537875 电脑配置: 解决这个问题的思路就是修改启动软件的JDK,有以下几个方法: ...
- OneZero第三次站立会议(2016.3.23)
会议时间:2016年3月23日 13:00~13:15 会议成员:冉华,张敏,王巍,夏一鸣. 会议目的:汇报前一天工作,全体成员评论并修改. 会议内容:以下为会议插图 1.界面原型方面,夏在统计界面中 ...