IEnumerable

我们每天都在使用foreach进行遍历,今天讨论下面三个常见的问题:

  • 为什么在foreach中不能修改item的值
  • 要实现foreach需要满足什么条件
  • 为什么Linq to Object中要返回IEnumerable类型

接下来,进入正题,首先我们先剖析下迭代器的内容,首先让我们创建一个迭代器

实现迭代器

.net中迭代器是通过IEnumerable和IEnumerator接口来实现的。首先让我们看下两个接口的面目

可以看出,IEnumerable只有一个返回了IEnumerator的方法GetEnumerator(),而IEnumerator中有两个方法加一个属性:MoveNext(),Reset(),Current

我们自己继承IEnumerable接口并实现:

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

可以看出分了三步:①获取IEnumerator接口实例,②判断是否可以继续循环,③取值

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

效果是等效的,通过反编译可以看出:

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

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

我们还记得IEnumerator的定义吗

接口的定义就只有get没有set。所以我们在foreach中不能修改item的值。

我们再来回答第二个问题:“要实现foreach需要满足什么条件?”:

是否必须实现IEnumerable接口?

答案是否。我们自己写的MyIEnumerable删掉后面的IEnumerable接口一样可以foreach

所以要可以foreach只需要对象定义了GetEnumerator无参方法,并且返回值是IEnumerator或其对应的泛型

注意只有方法名和返回类型


var ets = my.GetEnumerator();
while(ets.MoveNext())
{
Console.WriteLine(ets.Current);
}

也就是说,只要可以满足上面这三步调用即可。不一定要继承于IEnumerable

yield的使用

你肯定发现了我们自己去实现IEnumerator接口还是有些许麻烦,并且上面的代码肯定是不够健壮。

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

好家伙,我们之前写的那一大坨。你一个yield关键字就搞定了

我们继续来看GetEnumerator的定义和调用

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

现在我想可以回答你“为什么Linq to Object中要返回IEnumerable?”:

因为IEnumerable是延迟加载的,每次访问的时候才取值。也就是我们在Lambda里面写的where、select并没有循环遍历(只是在组装条件),只有在ToList或foreache的时候才真正去集合取值了。这样大大提高了性能。

如:

这个时候得到了就是IEnumerable对象,但是没有去任何遍历的操作。

我们再来做个实验,自己实现MyWhere:

执行到MyWhere的时候什么动作都没有(返回的就是IEnumerable),只有执行到ToList的时候才代码才真正的去遍历筛选。

原文

说下IEnumerable相关的的更多相关文章

  1. linux 下crontab相关定时触发的配置规则

    linux 下crontab相关定时触发的配置规则: 1.基本格式 :* * * * * command(分 时 日 月 周 命令)2.取值范围:分钟1-59 每分钟用*或者 */1表示小时1-23( ...

  2. 20145234黄斐《信息安全系统设计基础》第八周(Linux下vim相关命令)

    Linux下vim相关命令 在编辑程序时经常使用vim,所以记住一些常用的指令还是很有必要的 文件命令 vim file 打开单个文件vim file vim file1 file2 file3 .. ...

  3. Linux下mysql相关操作

    Linux下mysql相关操作 1.创建MySQL mysql -u root -p create user 'username'@'%' identified by 'password'; %可以选 ...

  4. Linux下 svn相关操作

    Linux下 svn相关操作 一.首先看看svn安装的位置: 命令: find / -name svn /var/svn :表示安装目录 /user/bin/svn :表示命令目录 可以看到的是svn ...

  5. linux下进程相关操作

    一.定义和理解 狭义定义:进程是正在运行的程序的实例. 广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动. 进程的概念主要有两点: 第一,进程是一个实体.每一个进程都有它自己的 ...

  6. Linux下Openfire相关安装和配置

    记录下来,方便下次再用时从头查找资料 小京东ecshop中的通讯有用到openfire,Window下配置安装很简单,直接下载exe文件安装就行,而linux下要麻烦一点.安装后的配置下面会细说: 一 ...

  7. windows环境下memcache相关配置及PHP加载相应模块(php7版本)

    原文:https://blog.csdn.net/zhangatle/article/details/77504094 亲测安装成功 php 7.0 nts 86 第一步,首先下载windows版本的 ...

  8. windows下数据挖掘相关包numpy、pandas的安装

    安装Anaconda的绕道 这里介绍如何在windows下安装numpy/scipy/matplotlib/pandas/scikit_learn等数据分析相关包 相关环境: win7 64位 pyt ...

  9. Linux下GCC相关知识点

    摘要: 总结GCC的具体使用,动态库静态库的相关问题 参考资料: <Linux网络编程> ISBN:9787302207177 p19 1 GCC简介 GCC是Linux下的编译工具集,是 ...

随机推荐

  1. GO语言学习(二)Windows 平台下 LiteIDE 的安装和使用

    1. 安装 Go 语言并设置环境变量 参考GO语言学习(一) 2. MinGW 的下载和安装 Windows 下的 Go 调试还需要安装 MinGW. 2.1 下载安装工具的安装 最新版本下载安装工具 ...

  2. HibernateCRUD基础框架(2)-HQL语句构造器(HqlQueryBuilder,HqlUpdateBuilder)

    上篇讲述了最基本的实体类,本篇接着讲述HQL语句构造器,包括查询和更新等. 优点:通过面向对象的方式构造HQL语句,更快捷,不需要手动拼接HQL. 缺点:封装可能降低性能,只能支持常用的和较为简单的H ...

  3. springboot整合freemarker(转)

    添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>sp ...

  4. 使用Samba在Linux服务器上搭建共享文件服务

    最近我们的小团队需要在服务器上共分出一个共享文件夹用于大家存放公共的资源文档, 大家想啊,这肯定很简单呀,在Windows下面只要创建相关的windows account,共享某个文件夹,把读/写权限 ...

  5. python的sorted() 函数

    摘自:http://www.runoob.com/python/python-func-sorted.html sortedClassCount=sorted(classCount.items(),k ...

  6. 过滤input框中的特殊字符

    两种方式,我觉得是一样的效果,请看: var charFilter1 = function(str) { var pattern = new RegExp("[`~!@#$^&*() ...

  7. POJ 1364 King (UVA 515) 差分约束

    http://poj.org/problem?id=1364 http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemi ...

  8. php实现数值的整数次方

    php实现数值的整数次方 一.总结 没有考虑到指数为负数的情况 二.php实现数值的整数次方 题目描述: 给定一个double类型的浮点数base和int类型的整数exponent.求base的exp ...

  9. 【u245】机房病毒

    Time Limit: 1 second Memory Limit: 128 MB [问题描述] 我们机房中了病毒,因此几乎什么都无法正常进入.为了解决这个病毒,我们花了好几天.终于在大家的共同努力下 ...

  10. php实现表示数值的字符串(is_numeric($s))

    php实现表示数值的字符串(is_numeric($s)) 一.总结 is_numeric($s) 二.php实现表示数值的字符串 题目描述 请实现一个函数用来判断字符串是否表示数值(包括整数和小数) ...