15.IEnumerable和IEnumerator
先说IEnumerable,我们每天用的foreach你真的懂它吗?
我们先思考几个问题:
- 为什么在foreach中不能修改item的值?
- 要实现foreach需要满足什么条件?
- 为什么Linq to Object中要返回IEnumerable?
接下来,先开始我们的正文。
自己实现迭代器
.net中迭代器是通过IEnumerable和IEnumerator接口来实现的,今天我们也来依葫芦画瓢。
首先来看看这两个接口的定义:


并没有想象的那么复杂。其中IEnumerable只有一个返回IEnumerator的GetEnumerator方法。而IEnumerator中有两个方法加一个属性。
接下来开发画瓢,我们继承IEnumerable接口并实现:

下面使用原始的方式调用:

有朋友开始说了,我们平时都是通过foreache来取值的,没有这样使用过啊。好吧,我们来使用foreach循环:

为什么说基本上是等效的呢?我们先看打印结果,在看反编译代码。


由此可见,两者有这么个关系:

我们可以回答第一个问题了“为什么在foreach中不能修改item的值?”:

我们还记得IEnumerator的定义吗

接口的定义就只有get没有set。所以我们在foreach中不能修改item的值。
我们再来回答第二个问题:“要实现foreach需要满足什么条件?”:
必须实现IEnumerable接口?NO

我们自己写的MyIEnumerable删掉后面的IEnumerable接口一样可以foreach(不信?自己去测试)。
所以要可以foreach只需要对象定义了GetEnumerator无参方法,并且返回值是IEnumerator或其对应的泛型。细看下图:

也就是说,只要可以满足这三步调用即可。不一定要继承于IEnumerable。有意思吧!下次面试官问你的时候一定要争个死去活来啊,哈哈!
yield的使用
你肯定发现了我们自己去实现IEnumerator接口还是有些许麻烦,并且上面的代码肯定是不够健壮。对的,.net给我们提供了更好的方式。

你会发现我们连MyIEnumerator都没要了,也可以正常运行。太神奇了。yield到底为我们做了什么呢?

好家伙,我们之前写的那一大坨。你一个yield关键字就搞定了。最妙的是这块代码:

这就是所谓的状态机吧!
我们继续来看GetEnumerator的定义和调用:

我们调用GetEnumerator的时候,看似里面for循环了一次,其实这个时候没有做任何操作。只有调用MoveNext的时候才会对应调用for循环:

现在我想可以回答你“为什么Linq to Object中要返回IEnumerable?”:
因为IEnumerable是延迟加载的,每次访问的时候才取值。也就是我们在Lambda里面写的where、select并没有循环遍历(只是在组装条件),只有在ToList或foreache的时候才真正去集合取值了。这样大大提高了性能。
如:

这个时候得到了就是IEnumerable对象,但是没有去任何遍历的操作。(对照上面的gif动图看)
什么,你还是不信?那我们再来做个实验,自己实现MyWhere:

现在看到了吧。执行到MyWhere的时候什么动作都没有(返回的就是IEnumerable),只有执行到ToList的时候才代码才真正的去遍历筛选。
这里的MyWhere其实可以用扩展方法来实现,提升逼格。(Linq的那些查询操作符就是以扩展的形式实现的)[了解扩展方法]。
怎样高性能的随机取IEnumerable中的值

这段代码来源《深入理解C#》,个人觉得非常妙。贴出来给大家欣赏哈。
转自https://www.cnblogs.com/zhaopei/p/5769782.html
15.IEnumerable和IEnumerator的更多相关文章
- 细说 C# 中的 IEnumerable和IEnumerator接口
我们先思考几个问题: 为什么在foreach中不能修改item的值? 要实现foreach需要满足什么条件? 为什么Linq to Object中要返回IEnumerable? 接下来,先开始我们的正 ...
- 迭代器学习之一:使用IEnumerable和IEnumerator接口
写博客是检验我学习的成果之一以及自我总结的一种方式,以后会经常利用这种方式进行技术交流和自我总结,其中认识不深难免会有错误,但是一直懂得不懂就问,不懂就学的道理! 1.首先看一个简单的列子 , , , ...
- C# ~ 从 IEnumerable / IEnumerator 到 IEnumerable<T> / IEnumerator<T> 到 yield
IEnumerable / IEnumerator 首先,IEnumerable / IEnumerator 接口定义如下: public interface IEnumerable /// 可枚举接 ...
- IEnumerable和IEnumerator
概述 IEnumerable和IEnumerator接口存在的意义:用来实现迭代的功能! public interface IEnumerable { IEnumerator GetEnumerato ...
- 关于迭代器中IEnumerable与IEnumerator的区别
首先是IEnumerable与IEnumerator的定义: 1.IEnumerable接口允许使用foreach循环,包含GetEnumerator()方法,可以迭代集合中的项. 2.IEnumer ...
- IEnumerable和IEnumerator 详解 (转)
原文链接:http://blog.csdn.net/byondocean/article/details/6871881 参考链接:http://www.cnblogs.com/hsapphire/a ...
- C#基础知识系列九(对IEnumerable和IEnumerator接口的糊涂认识)
前言 IEnumerable.IEnumerator到现在为止对这两个接口还是不太理解,不理解但是自己总是想着试着要搞明白,毕竟自己用的少,所以在此先记录一下.以备自己日后可以来翻查,同时也希望园子里 ...
- [转]那些年我还不懂:IList,ICollection,IEnumerable,IEnumerator,IQueryable
1.首先看一个简单的例子 int[] myArray = { 1, 32, 43, 343 }; IEnumerator myie = myArray.GetEnumerator(); myie.Re ...
- 转载IEnumerable与IEnumerator区别
public interface IEnumerable { IEnumerator GetEnumerator(); } public interface IEnumerator { ...
随机推荐
- 第四百一十五节,python常用排序算法学习
第四百一十五节,python常用排序算法学习 常用排序 名称 复杂度 说明 备注 冒泡排序Bubble Sort O(N*N) 将待排序的元素看作是竖着排列的“气泡”,较小的元素比较轻,从而要往上浮 ...
- 遍历一个Set的方法只有一个:迭代器(interator)。
Set-HashSet实现类: 遍历一个Set的方法只有一个:迭代器(interator). HashSet中元素是无序的(这个无序指的是数据的添加顺序和后来的排列顺序不同),而且元素不可重复. 在O ...
- Java分布式集群,使用synchronized和Redis保证Job的原子性
1.使用synchronized保证并发时,同时只会有一个请求执行该代码段: 2.在执行前先设置并获取Reids标记,先设置然后获取确保是否已经执行:SetOption.SET_IF_ABSENT 可 ...
- IE 浏览器不支持 ES6 Array.from(new Set( )) SCRIPT438: 对象不支持“from”属性
[转]解决老浏览器不支持ES6的方法 现象: Array.from(new Set( )) SCRIPT438: 对象不支持“from”属性或方法 解决方法: 安装babel 引入browser. ...
- error connecting: Timeout expired 超时时间已到. 达到了最大池大小 错误及Max Pool Size设置
[参考]Timeout expired 超时时间已到. 达到了最大池大小 错误及Max Pool Size设置 [参考][数据库-MySql] MySqlConnection error connec ...
- java递归算法提前返回值带出
/** * */ package testJava.java.foreach; import java.util.ArrayList; import java.util.LinkedList; imp ...
- windows下设置PHP环境变量
1.找到“高级系统设置”(二选一的方法找到环境变量) ① 我的电脑-属性-高级-环境变量 ②win8,10 直接在搜索框搜 “查看高级系统设置”-环境变量 2.找到变量"Path" ...
- MySQL的SQL预处理(Prepared)
Prepared SQL Statement:SQL的执行.预编译处理语法.注意点 一.SQL 语句的执行处理1.即时 SQL 一条 SQL 在 DB 接收到最终执行完毕返回,大致的过程如下: 1. ...
- 理解面向过程(OPP)、面向对象(OOP)、面向切面(AOP)
概念 面向过程编程OPP:Procedure Oriented Programming,是一种以事物为中心的编程思想.主要关注“怎么做”,即完成任务的具体细节. 面向对象编程OOP:Object Or ...
- flex布局应用与踩坑
一.预告 本文不是一篇入门的文章所有请符合以下条件的战斗人员绕道: 1.初学前端,对前端的传统布局还不是很熟悉的人 2.后端人员对前端不打算深入学习的同学 二.开篇 flex布局原本是好几个月前就一直 ...