C# 图解教程 第5版 —— 第19章 枚举器和迭代器

文章目录

    • 19.1 枚举器和可枚举类型
    • 19.2 IEnumerator 接口
    • 19.3 IEnumerable 接口
    • 19.4 泛型枚举接口
    • 19.5 迭代器
      • 19.5.1 迭代器块
      • 19.5.2 使用迭代器来创建枚举器
      • 19.5.3 使用迭代器来创建可枚举类型
    • 19.6 常见迭代器模式
    • 19.7 产生多个可枚举类型
    • 19.8 将迭代器作为属性
    • 19.9 迭代器的实质

19.1 枚举器和可枚举类型

使用 foreach 语句

​ 下面是使用 foreach 语句遍历数组的示例。

image-20231218145254811 image-20231218145309824

​ 数组可以使用这种方式访问的原因是:数组提供了枚举器对象。枚举器知道数组中元素的次序,并依次返回数组中的元素。

​ 对于有枚举器的类型而言,我们使用 GetEnumerator 方法来获取其拥有的枚举器,实现该方法的类型称为可枚举类型。数组就是可枚举类型。

image-20231218145604337
图19.1 枚举器和可枚举类型概览

​ foreach 结构设计用来和可枚举类型一起使用,如下行为会被执行:

  1. 调用 GetEnumerator 方法获取对象的枚举器。
  2. 从枚举起中请求每一项并作为迭代变量(可读不可写)。
image-20231218145810666

19.2 IEnumerator 接口

​ 实现了 IEnumerator 接口的枚举器包含 3 个函数成员:

  1. Current:返回序列中当前位置项的属性。
    • 为只读属性。
    • 返回 object 类型的引用。
  2. MoveNext:是将枚举器位置前进到集合中下一项的方法,返回布尔值。
    • 如果新的位置有效,返回 true。
    • 如果新的位置无效,返回 false。
  3. Reset:将位置重置为原始状态。
    • 枚举器的原始位置在序列中的第一项之前,因此 MoveNext 必须在第一次使用 Current 之前调用。
image-20231218150209771
图19.2 小集合的枚举器

​ 在编写 foreach 循环的时候,C# 编译器将生成与下面十分类似的代码(以 CIL 的形式)。

image-20231218150415769 image-20231218150445568
图19.3 .NET 数组类实现了 IEnumerator

19.3 IEnumerable 接口

​ 可枚举类是指实现了 IEnumerable 接口的类,该接口只有一个成员——GetEnumerator,返回对象的枚举器。

image-20231218150743647
图19.4 GetEnumerator 方法返回类的一个枚举器对象
image-20231218150941982

使用 IEnumerable 和 IEnumerator 的示例

image-20231218151148423 image-20231218151203527

19.4 泛型枚举接口

​ 使用 C# 泛型和非泛型的方式相差不大。

  • 对于非泛型接口形式:
    • IEnumerable 接口的 GetEnumerator 方法返回实现 IEnumerator 的枚举器类实例。
    • 实现 IEnumerator 的类实现了 Current 属性,返回 object 类型的引用,然后将其转化为对象的实际类型。
  • 对于泛型接口形式:
    • IEnumerable<T> 接口的 GetEnumerator 方法返回实现 IEnumerator<T> 的枚举器类实例。
    • 实现 IEnumerator<T> 的类实现了 Current 属性,返回实际类型的实例,而不是 object 基类的引用。
    • 实际上泛型接口的声明是协变的,即 IEnumerable<out T> 和 IEnumerator<out T>,因此这些接口的对象可以是派生的类型。

​ 泛型版本简单易用,但其结构略显复杂。

image-20231218151811109
图19.5 实现 IEnumerable<T> 接口的类的结构

19.5 迭代器

​ 可枚举类和枚举器在 .NET 集合类中被广泛使用,从 C# 2.0 版本开始提供了创建枚举器和可枚举类型更简单的方式,将这种结构称为迭代器

​ 在下面这个示例中:

  • 迭代器返回一个泛型枚举器,该枚举器返回 3 个 string 类型的项。
  • yield return 语句声明这是枚举中的下一项。
image-20231218152306099

​ 下面的方法声明了另一个版本,输出结果与上面相同。

image-20231218152341904

​ 枚举器不会一次返回所有的元素,而是每次访问 Current 属性时返回一个新值。

19.5.1 迭代器块

​ 迭代器块是有一个或多个 yield 语句的代码块,可以是如下任意一种代码块:

  • 方法主体。
  • 访问器主体。
  • 运算符主体。

​ 迭代器块描述了希望编译器为我们创建的枚举器类的行为,其中的代码描述了如何枚举元素。

  1. yield return:指定序列中要返回的下一项。
  2. yield break:指定在序列中没有其他项。

​ 编译器得到有关枚举项的描述后,会构建包含所有需要的方法(MoveNext)和属性(Current)实现的枚举器类,产生的类被嵌套包含在声明迭代器的类中。

image-20231218152851321
图19.6 根据指定的返回类型,可以让迭代器产生枚举器或可枚举类型

19.5.2 使用迭代器来创建枚举器

image-20231218153055412 image-20231218153138376
  • 图中左边演示了返回类型是 IEnumerator<string>。
  • 图中右边演示了它有一个嵌套类实现了 IEnumerator<string>。
image-20231218153301556
图19.7 迭代器块产生了枚举器

19.5.3 使用迭代器来创建可枚举类型

​ 本节例子使用迭代器来创建可枚举类型,而不是枚举器。

  • BlackAndWhite 迭代器方法返回 IEnumerable<string> 而不是 IEnumerator<string>。
  • MyClass 首先调用 BlackAndWhite 方法获取可枚举类型对象,然后调用该对象的 GetEnumerator 方法来获取结果,从而实现 GetEnumerator 方法。
image-20231218154115386
  • 图中左边演示了返回类型是 IEnumerable<string>。
  • 图中右边演示了它有一个嵌套类实现了 IEnumerator<string> 和 IEnumerable<string>。
image-20231218154355077
图19.8 编译器生成的类是可枚举类型并返回一个枚举器。编译器还生成了方法 BlackAndWhite,返回可枚举对象

19.6 常见迭代器模式

  1. 实现返回枚举器的迭代器。

    通过实现 GetEnumerator 方法让类可枚举,它返回由迭代器返回的枚举器。

  2. 实现返回可枚举类型的迭代器。

    实现 GetEnumerator 来让类本身可枚举;或不实现,来让类不可枚举。

image-20231218155301997
图19.9 常见的迭代器模式

19.7 产生多个可枚举类型

​ Spectrum 类有两个可枚举类型的迭代器,但类本身不可枚举,因为没有实现 GetEnumerator 方法。

image-20231218155441822 image-20231218155514934

19.8 将迭代器作为属性

​ 本示例演示两个方面的内容:

  1. 使用迭代器产生两个枚举器的类。
  2. 演示迭代器如何实现为属性,而不是方法。

​ 这段代码声明了两个属性来定义两个不同的枚举器。GetEnumerator 方法根据 _listFromUVtoIR 布尔变量的值返回两个枚举器中的一个。如果 _listFromUVtoIR 为 true,则返回 UVtoIR 枚举器;否则,返回 IRtoUV 枚举器。

image-20231218160024023 image-20231218160102546 image-20231218160121319

19.9 迭代器的实质

​ 有关迭代器的其他重要事项:

  • 迭代器需要 System.Collections.Generic 命名空间,因此需要使用 using 指令进行引入。
  • 在编译器生成的枚举器中,不支持 Reset 方法。Reset 是接口需要的方法,所以实现了它,但调用时总是抛出 System.NotSupportedException 异常。

​ 在后台,编译器生成的枚举器类总是包含 4 个状态的状态机。

  1. Before:首次调用 MoveNext 的初始状态。
  2. Running:调用 MoveNext 后进入这个状态。
    • 枚举器检测并设置下一项的位置。
    • 遇到 yield return、 yield break 或在迭代器中结束时,退出 Running 状态。
  3. Suspended:状态机等待下次调用 MoveNext 的状态。
  4. After:没有更多项可以枚举的状态。
image-20231218161138144
图19.10 迭代器状态机

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/230670.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【vSphere | VM】虚拟机自定义规范Ⅳ —— 使用虚拟机自定义规范创建 Linux 和 Windows VM

目录 5. 使用虚拟机自定义规范创建VM5.1 Linux 虚拟机示例Rocky Linux 9.2&#xff08;1&#xff09;克隆虚拟机&#xff08;2&#xff09;模板部署虚拟机 5.2 Windows 虚拟机示例Windows 10&#xff08;1&#xff09;克隆虚拟机&#xff08;2&#xff09;模板部署 Windows 10 …

恒创科技:云服务器怎么买才便宜有优惠

随着云计算技术的不断发展&#xff0c;云服务器已经成为企业和个人用户的重要选择。然而&#xff0c;在购买云服务器时&#xff0c;价格和优惠成为了很多用户关注的焦点。那么&#xff0c;如何购买云服务器才能获得更优惠的价格呢&#xff1f;下面就为大家介绍一些购买云服务器…

windows10-EMQX与MQTTX的安装及配置使用教程

windows10-EMQX安装及配置使用教程 一、下载安装1.1 下载1.2 安装1.3 设置开机自启动 二、连接MQTT2.1 MQTT下载安装2.1.1 下载2.1.2 安装及配置 三、EMQX常用命令 本文介绍的是在windows10系统下的emqx的安装、配置及使用教程。 一、下载安装 1.1 下载 下载链接&#xff1a…

【漏洞复现】金和OA任意文件读取漏洞

Nx01 产品简介 金和数字化智能办公平台&#xff08;简称JC6&#xff09;是一款结合了人工智能技术的数字化办公平台&#xff0c;为企业带来了智能化的办公体验和全面的数字化转型支持。同时符合国家信创认证标准&#xff0c;支持组织数字化转型&#xff0c;实现业务流程的数字化…

订单未支付30分钟自动取消是如何实现的?

1.借助redis的过期特性 下单时&#xff0c;订单状态是待支付。将订单编号作为key&#xff0c;下单的时间戳作为value&#xff0c;设置过期时间是30分钟。服务器监听redis的key过期事件&#xff0c;如果是订单过期&#xff08;还会有其他key过期&#xff09;&#xff0c;则修改…

AI伴侣利用亚马逊云科技机器学习与人工智能服务,加速AI类产品的开发过程

2020年《纽约时报》调查显示&#xff0c;全球有超过1000万人以AI恋人作为伴侣&#xff1b;后浪发布的《2022年轻人未来恋爱白皮书》报告中显示&#xff0c;有近4成年轻人接受与虚拟人恋爱。随着人工智能技术的突破&#xff0c;越来越多年轻群体在AI伴侣软件亲手打造自己的理想恋…

API调试神器!免费IDEA插件推荐

IDEA是一款功能强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;它可以帮助开发人员更加高效地编写、调试和部署软件应用程序。我们在编写完接口代码后需要进行接口调试等操作&#xff0c;一般需要打开额外的调试工具。 今天给大家介绍一款IDEA插件&#xff1a;Api…

智能优化算法应用:基于风驱动算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于风驱动算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于风驱动算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.风驱动算法4.实验参数设定5.算法结果6.参考文…

终于知道灵活自助分析的BI报表是怎么做的了

不知道是不是临近年底要做年终分析报告的原因&#xff0c;最近很多小伙伴都来咨询BI报表怎么做的问题。其实BI报表还真的只需点击、拖拉拽就能完成。接下来就来简单地说几个做BI报表都需要注意的事项。 BI报表制作流程&#xff1a; 1、连接数据源&#xff0c;奥威BI大数据分析…

2023_Spark_实验二十九:Flume配置KafkaSink

实验目的&#xff1a;掌握Flume采集数据发送到Kafka的方法 实验方法&#xff1a;通过配置Flume的KafkaSink采集数据到Kafka中 实验步骤&#xff1a; 一、明确日志采集方式 一般Flume采集日志source有两种方式&#xff1a; 1.Exec类型的Source 可以将命令产生的输出作为源&…

使用好的GPU的优点

最近改论文&#xff0c;需用重新训练模型&#xff0c;采用自己电脑来训练。结果一周没有出结果&#xff0c;用大电脑处理&#xff0c;一天完成所有模型的训练。 大家看看下面的结果就知道差异了。 数据集大小有差异&#xff0c;但不大。 4090 的结果 3060的结果

HarmonyOS(十三)——详解自定义组件的生命周期

前言 自定义组件的生命周期回调函数用于通知用户该自定义组件的生命周期&#xff0c;这些回调函数是私有的&#xff0c;在运行时由开发框架在特定的时间进行调用&#xff0c;不能从应用程序中手动调用这些回调函数。 下图展示的是被Entry装饰的组件生命周期&#xff1a; 今…

ai生成动漫头像的软件有哪些?这5个简单好用

ai生成动漫头像的软件有哪些&#xff1f;随着科技的飞速发展&#xff0c;AI技术已经渗透到我们生活的方方面面。如今&#xff0c;它甚至可以帮助我们轻松生成动漫头像。如果你也是动漫迷&#xff0c;或者想为自己的社交媒体账号添加一些个性化的元素&#xff0c;那么接下来要介…

2023本四前端社招面经

美团 全程问项目&#xff0c;根据项目提问&#xff0c;SEO优化方案&#xff0c;还出了一道动态规划的题 SEO优化方案 一、内部优化 META 标签优化&#xff1a;例如&#xff1a;TITLE&#xff0c;KEYWORDS&#xff0c;DESCRIPTION &#xff08;TDK&#xff09;等的优化 内部链接…

在vue中通过js动态绘制table,并且合并连续相同内容的行

首先是vue代码 <template><div id"body-container"style"position: absolute"><div class"box-container"><div class"lsb-table-box" ><div class"table-container" id"lsb-table"&…

检测当前目录,将文件名输出到excel文件并建立链接

EXCEL是一个非常使用的软件,虽然我们平时仅使用他做一些报表,仅此而已; 我在工作中,由于很懒,不愿意做考试重复的工作,就想着使用vba的宏来完成重复的工作,这样就能省出一部分的时间来了。 本人不喜欢在博客里面写以下教程类的东西,我的理念是将工作中的痛点的解决办法…

说一下 jvm 有哪些垃圾回收算法?

说一下 jvm 有哪些垃圾回收算法&#xff1f; 一.对象是否已死算法 1.引用计数器算法 2.可达性分析算法 二.GC算法 1.标记清除算法 如果对象被标记后进行清除&#xff0c;会带来一个新的问题–内存碎片化。如果下次有比较大的对象实例需要在堆上分配较大的内存空间时&#xff0…

【网络安全】-Linux操作系统—VMWare软件

文章目录 VMWare软件的安装选择VMWare版本下载VMWare安装过程 VMWare的常用操作创建新的虚拟机配置虚拟机启动和关闭虚拟机安装VMWare Tools VMWare的克隆和快照克隆&#xff08;Clone&#xff09;快照&#xff08;Snapshot&#xff09; 总结 VMWare是一种流行的虚拟化软件&…

13个数据可视化工具 一键生成可视化图表

前言 数字经济时代&#xff0c;我们每天正在处理海量数据&#xff0c;对数据可视化软件的需求变得突出&#xff0c;它可以帮助人们通过模式、趋势、仪表板、图表等视觉辅助工具理解数据的重要性。 如果遇到数据集需要分析处理&#xff0c;但是你不又知道选择何种数据可视化工…

LoadRunnder-VUG

WebTours启动VUG脚本录制脚本删除运行回放脚本增强1&#xff1a;事务插入2&#xff1a;插入集合点3&#xff1a;插入检查点4&#xff1a;参数化5&#xff1a;打印日志 WebTours启动 WebTours系统&#xff1a;LoadRunner自带的系统&#xff1b;为了让用户能熟悉它这个工具&…