我们先思考几个问题:

  1. 为什么在foreach中不能修改item的值?
  2. 要实现foreach需要满足什么条件?
  3. 为什么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#》,个人觉得非常妙。贴出来给大家欣赏哈。

结束:

demo下载:http://pan.baidu.com/s/1dE94c1b

接下篇:《再讲IQueryable<T>,揭开表达式树的神秘面纱

IEnumerable 使用foreach 详解的更多相关文章

  1. IEnumerable和IEnumerator 详解 分类: C# 2014-12-05 11:47 18人阅读 评论(0) 收藏

    原:<div class="article_title"> <span class="ico ico_type_Original">&l ...

  2. <c:forEach>详解

    <c:forEach>详解 <c:forEach>标签的语法定义如下所示. <c:forEach var="name" items="exp ...

  3. myBatis foreach详解【转】

    MyBatis的foreach语句详解 foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合.foreach元素的属性主要有 item,index,collection,ope ...

  4. IEnumerable和IEnumerator 详解 (转)

    原文链接:http://blog.csdn.net/byondocean/article/details/6871881 参考链接:http://www.cnblogs.com/hsapphire/a ...

  5. IEnumerable和IEnumerator 详解

    初学C#的时候,老是被IEnumerable.IEnumerator.ICollection等这样的接口弄的糊里糊涂,我觉得有必要切底的弄清楚IEnumerable和IEnumerator的本质. 下 ...

  6. IEnumerable和IEnumerator 详解 【转】

    初学C#的时候,老是被IEnumerable.IEnumerator.ICollection等这样的接口弄的糊里糊涂,我觉得有必要切底的弄清楚IEnumerable和IEnumerator的本质. 下 ...

  7. 转载 IEnumerable和IEnumerator 详解

    初学C#的时候,老是被IEnumerable.IEnumerator.ICollection等这样的接口弄的糊里糊涂,我觉得有必要切底的弄清楚IEnumerable和IEnumerator的本质. 下 ...

  8. IEnumerable和IEnumerator详解

    引言 IEnumerable是可枚举的所有非泛型集合的基接口, IEnumerable包含一个方法GetEnumerator(),该方法返回一个IEnumerator:IEnumerator提供通过C ...

  9. <c:forEach> 详解

    <c:forEach>标签用于通用数据循环,它有以下属性 属 性 描 述 是否必须 缺省值 items 进行循环的项目 否 无 begin 开始条件 否 0 end 结束条件 否 集合中的 ...

随机推荐

  1. javascript的基本语法、数据结构

    本篇学习资料主要讲解javascript的基本语法.数据结构      无论是传统的编程语言,还是脚本语言,都具有数据类型.常量和变量.运算符.表达式.注释语句.流程控制语句等基本元素构成,这些基本元 ...

  2. HTTPS 原理解析(转)

    一 前言 在说HTTPS之前先说说什么是HTTP,HTTP就是我们平时浏览网页时候使用的一种协议.HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全.为了保证 ...

  3. Android Drawable

    1. Shape 属性: (1) solid ( 填充 ) 参数:android:color ( 填充的颜色 ) (2) gradient ( 渐变 ) 参数:android:startColor ( ...

  4. ACM 心急的C小加

    心急的C小加 时间限制:1000 ms  |  内存限制:65535 KB 难度:4   描述 C小加有一些木棒,它们的长度和质量都已经知道,需要一个机器处理这些木棒,机器开启的时候需要耗费一个单位的 ...

  5. HDU - 人见人爱A^B

    Description 求A^B的最后三位数表示的整数. 说明:A^B的含义是“A的B次方”  Input 输入数据包含多个测试实例,每个实例占一行,由两个正整数A和B组成(1<=A,B< ...

  6. unix network programming volume1 sorce code build and get(UNIX網絡編程卷1第三版)

    source code下载地址:unpv13e.tar.gz下载 (也有放一份在google cloud storage) compile 1. ./configure 2. cd lib make ...

  7. Cloudera Manager 5和CDH5离线安装

    CDH (Cloudera’s Distribution, including Apache Hadoop),是Hadoop众多分支中的一种,由Cloudera维护,基于稳定版本的Apache Had ...

  8. Digital Imaging Processing 数字图像处理

    8-Bit and 16-Bit Images 关于量化压缩与量化补偿 RGB Bayer Color分析 彩色CCD/CMOS的格式和计算机中的读取格式

  9. 简单的自定义Adapter

    import android.content.Context; import android.view.LayoutInflater; import android.view.View; import ...

  10. u盘安装windows系统

    使用老毛桃为例: 电脑下载老毛桃到自己电脑,插入U盘,制作U盘为启动盘. 四种安装方法: 1.win7能够使用:(win中包含iso的解压文件)解压ISO ----〉 restart win7 --- ...