网站首页 > 开源技术 正文
迭代器,我想大家都听说过,但是我想这块内容很容易让人忽视,或许你每天都在用,但是你不自知。我想你肯定知道什么是foreach,因为这个你每天都在用。你肯定看到过IEnumerable,IEnumerator这两个接口,看到过关键字yield,但是或许你只是在一些微软提供的数据结构里面看到过,你自己并没有去实现过。
迭代器是一种设计模式,并不是语言层面的。我想说的意思是迭代器不局限编程语言,也就是他不是C#专有,其他很多语言都可以实现。他的目的是"构建出一个数据管道,把源头数据通过一系列的转换和过滤变成你想要的数据",为什么我要用引号,因为这句话并不好理解。首先在C#里面,只要实现了IEnumerable的类就是实现了迭代器设计模式的类,就能够在foreach里面遍历。反过来说,能放在foreach遍历的对象都是实现了IEnumerable的迭代器类,而IEnumerable实现类里面利用了IEnumerator这个实现体,所以IEnumerable 和 IEnumerator是密不可分的。但是C#里面一定是只能实现了IEnumerable,IEnumerator才是实现了迭代器吗,当然不是,我说了迭代器是设计模式,不局限于C#,js都可以。
接下来我通过几个例子说明怎么使用,请看下图。
不忘初心,方得始终,我接下来举的所有例子的目的都是在说明迭代器的作用,就是那句话。"构建出一个数据管道,把源头数据通过一系列的转换和过滤变成你想要的数据"。
请看上图3,4,我想要把"a","b","c","d","e"这个数组按照我想要的顺序显示出来,比如按照"c"开头的,"c","d","e","a","b",前者的数据是"源头数据",后者是"你想要的数据"。我构建了两个类
InterationSample,InterationSampleIterator,
前者实现了IEnumerable,后者实现了IEnumerator。我们先看看这两个接口定义的方法,请看图1,图2。 两个接口都很简单,
IEnumerable定义了一个方法GetEnumerator,返回IEnumerator接口.。
IEnumerator接口定义了两个方法和一个属性,我们看这两个实现类。
InterationSample实现了GetEnumerator,返回的是IEnumerator接口,
也就是IterationSampleIterator这个类,
InterationSample构造函数两个参数,一个是原始数据数组,
另外一个是输出数据的起始标记位。
IterationSample很简单,foreach循环开始,
首先会调用GetEnumerator方法获取IEnumerator对象,然后执行MoveNext方法,判断是否需要继续执行下去。
"position++"之后position等于4,
"var ret = position <= parent.startingPoint + parent.values.Length;"
"parent.startingPoint"是3,
"parent.values.Length"是5,
那么4<8成立,说明迭代器继续。为什么这么判断,我们先看后面的代码。
当然MoveNext方法返回true,那么foreach就会取Current这个属性的值。
可以看出来,"index=position",等于4,然后
"index=(index-2)%parent.values.Length",
"index=(4-2)%5",
取余数等结果等于2。
然后返回"parent.values[index]"也就是第三个数据"c"。看结果图5,显示出来了"c",
也就是Current的属性值给了foreach里面变量x,所以显示出来"c"。
这个也是我们预期的,因为我们正想从"c"开始输出。接着继续执行MoveNext方法,
"position++"之后position等于5,
"var ret = position <= parent.startingPoint + parent.values.Length;"
"parent.startingPoint"是3,
"parent.values.Length"是5,
那么5<=8成立。
说明迭代器继续,然后调用Current get属性,
"index=(index-2)%parent.values.Length",
"index=(5-2)%5",
取余数等结果等于3,
然后返回"parent.values[index]"也就是第三个数据"d"。
因为Current获取数组的数据是按照索引来的,所以通过取余方式获取索引比较合适,这也 说明为什么MoveNext方法要用
"var ret = position <= parent.startingPoint + parent.values.Length;"
这句话进行判断了。大家想一下这个逻辑就知道了。
大家可能对于foreach怎么运行代码搞不清楚,才导致理解上面的例子需要有点时间。那么我换另外一种方式遍历迭代器。请看下图。
这个代码就清晰多了,而且和我们上面描述的过程是一样的,结果也是一样的。我想这个代码非常清楚就不再描述了。
看到这里你有没有感到疑问?要实现从"a","b","c","d","e"到"c","d","e","a","b"的转换,或者"d","e","a","b","c",我tm需要搞得这么复杂么,我使用for循环也就几行代码就搞定了。我想和你说是的,我们确实第一念头就是直接通过for循环,写的代码也少。但是我想和你说的是,这里我只是想要循序渐进地往下说,慢慢你就明白用迭代器的好处在哪里了。我们回过头再看看这个代码。
确实代码有点多,现在我要引入yield关键字了。请看下图。
先说明一下,foreach C#1.0就有了,也就是上面的代码C#1.0大体就能运行。yield是C#2.0才引入的。请看下面的C#各个版本升级的内容
让你明白yield关键字的作用,我还得和你说另外一个话题,就是C#代码执行的过程,这里我想长话短说。首先C#编译器会将C#代码编译成IL(中间语言),元数据。dll大家都知道,他里面大体就是这两样东西。我想只介绍IL语言,因为这个话题应该另外起一个文章介绍才行。
IL到底是个啥,有什么用呢?原因就是因为.NET平台不止C#一种语言,还有vb,f#等很多种语言,你开心的话你也可以搞一个语言出来。那么这些语言语法会有不同,微软就想要通过一个中间语言统一这些语言,让这些语言通过各自编译器生成一样的代码,也就是IL中间语言。那么后面这些代码就统一处理了。也就是微软说我支持你发明一个新语言,我不管你发明的语言是中文还是汉语我都不在乎,只要你的编译器生成的代码是IL代码,那么就可以在我.NET平台运行。执行的过程会用到JIT编译器,会将IL代码生成机器语言,也就是汇编语言,这样cpu就可以执行了。
为什么我要扯开话题聊一下C#代码执行过程,就是因为在我们学习过程中会发现C#一直在升级,目前.NET6 已经到了C# 10,各种语法糖让我们更加方便地使用,但是也增加了复杂度(都是一些什么玩意每天升级让人一直得去学习)。但是我想告诉大家的是,IL语言改变不大,IL归根到底还是高级语言,有类,对象,方法,字段,属性,事件,委托等,也就是说不管C#再怎么升级,都是编译器变的魔术,最终生成的IL语言和前面版本的C#是差不多的。当然异步函数也是编译器变的一种魔术。
IL语言我们可以通过工具生成,这里我用的是ilspy,也就是dll生成IL,然后也有工具可以从IL生成C#代码,可以使用IL dasm。我们接下来把这个代码,生成IL。
这里我不解释IL语言了,这是另外一个章节需要讲的事情了。
今日头条文章有字数限制,接下来请看
C#核心-迭代器揭秘2
- 上一篇: C#核心-迭代器揭秘2(c#迭代法求e)
- 下一篇: [WPF]总结一些我在开发WPF时常用的工具
猜你喜欢
- 2024-09-30 C# new(new)
- 2024-09-30 .NET-每周精选(net定时任务)
- 2024-09-30 为什么要用内插字符串代替string.format?
- 2024-09-30 为什么要用内插字符串代替string.format
- 2024-09-30 过早的给方法中 引用对象 设为 null 可被 GC提前回收吗?
- 2024-09-30 推荐几个对Asp.Net开发者比较实用的工具 2
- 2024-09-30 [WPF]总结一些我在开发WPF时常用的工具
- 2024-09-30 C#核心-迭代器揭秘2(c#迭代法求e)
- 2024-09-30 C# 9 中又来一堆关键词 init,record,with
- 2024-09-30 代码安全之代码混淆(代码混淆器到底是不是病毒)
你 发表评论:
欢迎- 最近发表
-
- 使用Python实现图片文件的加密与解密:保障隐私安全的实用方案
- 吴恩达官宣开源,yyds!(吴恩达rnn)
- Python自动化办公实战:效率提升10倍的脚本开发指南
- Android让视图显示未读消息数量(未读消息图标怎么显示)
- docker容器安装与部署,常用命令、容器卷、dockerfile,详细教程
- pytorch的一个最简单的cpp扩展(pytorch cdist)
- 如何编译.Net 6 Runtime源码(编译framework)
- 微软Windows 11将改版BSOD、强制登录账号才能安装
- windows环境下配置sphinx输出html文档
- 超详细windows安装配置WSL2(ubuntu20.04)步骤
- 标签列表
-
- jdk (81)
- putty (66)
- rufus (78)
- 内网穿透 (89)
- okhttp (70)
- powertoys (74)
- windowsterminal (81)
- netcat (65)
- ghostscript (65)
- veracrypt (65)
- asp.netcore (70)
- wrk (67)
- aspose.words (80)
- itk (80)
- ajaxfileupload.js (66)
- sqlhelper (67)
- express.js (67)
- phpmailer (67)
- xjar (70)
- redisclient (78)
- wakeonlan (66)
- tinygo (85)
- startbbs (72)
- webftp (82)
- vsvim (79)
本文暂时没有评论,来添加一个吧(●'◡'●)