IL角度理解for 与foreach的区别——迭代器模式
IL角度理解for 与foreach的区别——迭代器模式
1 最常用的设计模式
1.1 背景
如果问你最常用的设计模式是哪种?你可能会说单例模式,工厂模式。但根据我在项目里的经验,一个完整的应用,应该是迭代器模式。
1.2 摘要
- 本文不讲怎么去实现迭代器模式,但介绍迭代器模式到底是什么?为什么迭代器循环迭代时,无法删除元素,无法修改元素;
- 本文讲的迭代器,媒介主要是C#语言下的foreach,微软爸爸已经在C#的foreach中帮我们实现了迭代器代码,关于迭代器,我们只需要知道他是什么,他的特性是什么,为什么要用他?
- 迭代器有什么优点,有什么缺点?
- 在本文中迭代器模式约等于foreach
2 遍历元素
在本项中将会带大家一起进入迭代器模式下的IL代码,看看迭代器内部是怎么去进行循环迭代的;
如下代码实现了for循环打印集合中的所有元素,以及foreach迭代打印集合中的所有元素。
static void Main(string[] args)
{
List<int> intList = new List<int>();
intList.Add(1);
intList.Add(2);
for(var i=0;i<intList.Count;i++)
{
Console.WriteLine("元素for遍历打印:" + intList[i]);
}
foreach (var item in intList)
{
Console.WriteLine("元素foreach遍历打印:" + item);
}
}
代码输出:

可以看到两种打印方式效果一致;for循环任一一种语言都有,大家再熟悉不过,这里不再赘述,我们来看下foreach迭代器模式的IL代码;

大概思路如下:List 下有个迭代器Enumerator,可以通过List下的GetEnumerator方法获得此迭代器集合;然后通过迭代器的get_Current方法来获取当前第一个元素。迭代器的MoveNext()方法判断下一元素是否存在,如果存在取出循环;不存在结束迭代循环模式;最终,将迭代过程中产生的系统非托管资源释放;
迭代器代码如下:
var enumerator = intList.GetEnumerator();
while (enumerator.MoveNext())
{
Console.WriteLine("迭代器模式遍历打印:" + enumerator.Current);
}
Console.ReadLine();
3 删除元素
3.1 for删除例子
List<int> intList = new List<int>();
intList.Add(1);
intList.Add(2);
for(var i=0;i<intList.Count;i++)
{
if (intList[i] == 1)
{ intList.Remove(1); }
}
Console.WriteLine("集合中元素数量:" + intList.Count);
Console输出
集合中元素数量:1
这说明for删除成功
3.2 foreach删除例子
foreach (var item in intList)
{
if (item==1)
{ intList.Remove(1); }
}
Console.WriteLine("集合中元素数量:" + intList.Count);

从如上抛出的异常得得知 var enumerator = intList.GetEnumerator();迭代器在循环迭代中是不允许对该迭代器进行删除操作的。如果需要删除操作,可以再这个集合基础上做linq操作;因为迭代器在循环迭代中是一个值对象的存在,不允许变更迭代器对象的内容;
思考
如下代码也是运用了迭代器模式,为什么能删除集合元素了?读者自行思考哈。这也是迭代器方式下牺牲内存来删除/修改元素的一种方法。
foreach (var item in dictionary.ToList()) {
Debug.Log(item.Key + "," + item.Value);
if (item.Key.Equals("s11")) {
dictionary.Remove(item.Key);
}
}
4 修改元素
4.1 for修改
List<int> intList = new List<int>();
intList.Add(1);
intList.Add(2);
for(var i=0;i<intList.Count;i++)
{
if (intList[i] == 1)
{ intList[i]=3; }
Console.WriteLine("集合中元素遍历:" + intList[i]);
}
输出:
集合中元素遍历:3
集合中元素遍历:2
从如上输出看出,for修改成功
4.2 foreach修改
直接编译就通不过

5 修改元素属性
如下程序,会去修改迭代器元素的属性,并且在for跟foreach下都能运行成功。
class Program
{
static void Main(string[] args)
{
List<protocol> protocols = new List<protocol>();
var p1 = new protocol();
p1.bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
var p2 = new protocol();
p2.bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
protocols.Add(p1);
protocols.Add(p2);
foreach (var item in protocols)
{
item.bytes = p2.bytes;
item.intList.Add(1);
}
for (var i=0;i<protocols.Count;i++)
{
protocols[i].bytes = p1.bytes;
protocols[i].intList.Add(1);
protocols[i] = p1;
}
Console.WriteLine("程序运行成功");
Console.ReadLine();
}
}
public class protocol
{
public byte[] bytes= { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
public List<int> intList=new List<int>();
}
6 什么场景下用foreach
既然,for效率更高,foreach效率不及for。for能做的事foreach不能做(修改删除元素)。是不是没有foreach的用武之地了呢,大错特错了,恰恰相反,每个项目里用的最多的反而是foreach迭代器模式,我统计了下超过工厂模式跟单例模式,不信你自己去数foreach的数量。但是在遍历散列集合时,如字典,for就会失效了,因为下标不是有序数值了,而是看上去无序的内部散列算法。这时foreach遍历字典就很有用,他定义了一个枚举器(迭代器),而这个枚举器统一了,getCurrent(), moveNext()等用于迭代的方法;
foreach (var item in dictionary.ToList()) {
Debug.Log(item.Key + "," + item.Value);
if (item.Key.Equals("s11")) {
dictionary.Remove(item.Key);
}
}
像上面的用for,for循环的i与字典的key(自定义,一般是string类型)是没办法建立映射关系的;所以无法用for循环
7 小结
- for与foreach都可以遍历数组/集合,不过for则在较复杂的循环中效率更高;
- foreach不可以删除/修改集合元素,而for可以;
- foreach和for都可以修改元素里面的属性;
- foreach适合遍历用了哈希算法的散列,集合,字典;
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://www.cnblogs.com/JerryMouseLi/p/13977500.html
IL角度理解for 与foreach的区别——迭代器模式的更多相关文章
- IL角度理解C#中字段,属性与方法的区别
IL角度理解C#中字段,属性与方法的区别 1.字段,属性与方法的区别 字段的本质是变量,直接在类或者结构体中声明.类或者结构体中会有实例字段,静态字段等(静态字段可实现内存共享功能,比如数学上的pi就 ...
- (十七)迭代器模式详解(foreach的精髓)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 各位好,很久没以LZ的身份和 ...
- 设计模式之迭代器模式详解(foreach的精髓)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 各位好,很久没以LZ的身份和 ...
- 十七:迭代器模式详解(foreach的精髓)
定义:提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示. 从定义中可以看出,迭代器模式是为了在不暴露该对象内部表示的情况下,提供一种顺序访问聚合对象中元素的方法.这种思想在JA ...
- 从IL角度彻底理解回调_委托_指针
从IL角度彻底理解回调_委托_指针 目录 从IL角度彻底理解回调_委托_指针 1.创作此文的背景 1.1.委托能帮助代码更好地封装 1.2.委托能随时随地更方便地运行其他类中的方法 1.3.委托非常适 ...
- 从tcp原理角度理解Broken pipe和Connection reset by peer的区别
从tcp原理角度理解Broken pipe和Connection reset by peer的区别 http://lovestblog.cn/blog/2014/05/20/tcp-broken-pi ...
- 【.Net底层剖析】3.用IL来理解属性
.Net底层剖析目录章节 1.[深入浅出.Net IL]1.一个For循环引发的IL 2.[.Net底层剖析]2.stfld指令-给对象的字段赋值 3.[.Net底层剖析]3.用IL来理解属性 未完待 ...
- 转:如何学习SQL(第二部分:从关系角度理解SQL)
转自:http://blog.163.com/mig3719@126/blog/static/285720652010950825538/ 6. 从关系角度理解SQL 6.1. 关系和表 众所周知,我 ...
- IL来理解属性
IL来理解属性 阅读目录 概述: C#中如何定义一个属性 Student类 属性Name Main方法 实现get,set方法 性能 访问权限 回到最开始提出的问题 参考资料 .Net底层剖析目录 ...
随机推荐
- Docker笔记5:实现加速器,加快下载/拉取镜像速度
由于 Docker 官方仓库存储于国外服务器,因此,我们使用d ocker pull 命令拉取镜像时,速度很慢.但是,我们可以使用国内服务商提供的加速器进行加速,加速器实质是一个IP地址,将其加入到d ...
- ansible-playbook文件复用
1. ansible-playbook文件复用 1.1) include 和 import区别 include(动态):在运行时导入 --list-tags,--list-tasks不会显示到输出 ...
- Hybrid App中原生页面 VS H5页面
Hybrid App中原生页面 VS H5页面 现有3类主流APP,分别为:Web App.Hybrid App(混合模式移动应用,Hybrid有"混合的"意思). Nativ ...
- spring boot:spring security给用户登录增加自动登录及图形验证码功能(spring boot 2.3.1)
一,图形验证码的用途? 1,什么是图形验证码? 验证码(CAPTCHA)是"Completely Automated Public Turing test to tell Computers ...
- spring boot:使mybatis访问多个druid数据源(spring boot 2.3.2)
一,为什么要使用多个数据源? 1,什么情况下需要使用多个数据源? 当我们需要访问不同的数据库时,则需要配置配置多个数据源, 例如:电商的业务数据库(包括用户/商品/订单等) 和统 ...
- centos8平台:用fontconfig安装及管理字体(fc-list/fc-match/fc-cache)
一,fc-list所属的rpm包 [root@blog ~]$ whereis fc-list fc-list: /usr/bin/fc-list /usr/share/man/man1/fc-lis ...
- docker19.03搭建私有容器仓库
一,启动docker后,搜索registry [root@localhost source]# systemctl start docker [root@localhost source]# dock ...
- Linux基础命令之getent
getent命令简述 getent - get entries(entry的复数,条目.项目.记载.记录) getent命令可以用来察看系统的数据库中的相关记录 经常使用getent查看用户账号: 之 ...
- JS实现鼠标移入水波效果
前言 最近比较沉迷JS,所以我现在来做个鼠标的交互效果 HTML <div style="border-radius;position:relative;width:800px;hei ...
- 如何实现 axios 的自定义适配器 adapter
Axios 是一个非常优秀的基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中.并且提供了很多便捷的功能,例如: 支持 Promise API 拦截请求和响应 转换请求数据和 ...