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

news2024/11/25 17:20:29

文章目录

    • 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.coloradmin.cn/o/1321190.html

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

相关文章

Postman使用总结--参数化

将 测试数据&#xff0c;组织到 数据文件中&#xff0c;通过脚本的反复迭代&#xff0c;使用不同的数据&#xff0c;达到测试不同用例的目标 数据文件有两种&#xff1a; CSV &#xff08;类似于excel&#xff09; 格式简单用这个 文件小 JSON&#xff08;字典列表&#x…

Vue3-22-组件-插槽的使用详解

插槽是干啥的 插槽 就是 组件中的一个 占位符&#xff0c; 这个占位符 可以接收 父组件 传递过来的 html 的模板值&#xff0c;然后进行填充渲染。 就这么简单&#xff0c;插槽就是干这个的。要说它的优点吧&#xff0c;基本上就是可以使子组件的内容可以被父组件控制&#xf…

Amazon CodeWhisperer 体验

文章作者&#xff1a;jiangbei 1. CodeWhisperer 安装 1.1 先安装 IDEA&#xff0c;如下图&#xff0c;IDEA2022 安装为例&#xff1a; 亚马逊云科技开发者社区为开发者们提供全球的开发技术资源。这里有技术文档、开发案例、技术专栏、培训视频、活动与竞赛等。帮助中国开发者…

MongoDB中的关系

本文主要介绍MongoDB中的关系。 目录 MongoDB的关系嵌入关系引用关系 MongoDB的关系 MongoDB是一个非关系型数据库&#xff0c;它使用了键值对的方式来存储数据。因此&#xff0c;MongoDB没有像传统关系型数据库中那样的表、行和列的概念。相反&#xff0c;MongoDB中的关系是通…

主馆位置即将售罄“2024北京国际信息通信展会”众多知名企聚京城

2024北京国际信息通信展&#xff0c;将于2024年9月份在北京国家会议中心盛大召开。作为全球信息通信技术领域的重要盛会&#xff0c;此次展会将汇集业内顶尖企业&#xff0c;展示最新的技术成果和产品。 目前&#xff0c;主馆位置即将售罄&#xff0c;华为、浪潮、中国移动、通…

数据结构(Chapter Two -02)—顺序表基本操作实现

在前一部分我们了解线性表和顺序表概念&#xff0c;如果有不清楚可以参考下面的博客&#xff1a; 数据结构(Chapter Two -01)—线性表及顺序表-CSDN博客 首先列出线性表的数据结构&#xff1a; #define MaxSize 50 //定义顺序表最大长度 typedef struct{ElemType data…

【面试】Java最新面试题资深开发-微服务篇(1)

问题九&#xff1a;微服务 什么是微服务架构&#xff1f;它与单体架构相比有哪些优势和劣势&#xff1f;解释一下服务发现和服务注册是什么&#xff0c;它们在微服务中的作用是什么&#xff1f;什么是API网关&#xff08;API Gateway&#xff09;&#xff1f;在微服务中它有何…

什么是关键词排名蚂蚁SEO

关键词排名是指通过搜索引擎优化&#xff08;SEO&#xff09;技术&#xff0c;将特定的关键词与网站相关联&#xff0c;从而提高网站在搜索引擎中的排名。关键词排名对于网站的流量和用户转化率具有至关重要的影响&#xff0c;因此它是SEO工作中最核心的部分之一。 如何联系蚂…

任务十六:主备备份型防火墙双机热备

目录 目的 器材 拓扑 步骤 一、基本配置 配置各路由器接口的IP地址【省略】 1、配置BGP协议实现Internet路由器之间互联 2、防火墙FW1和FW2接口IP配置与区域划分 3、配置区域间转发策略 4、配置NAPT和默认路由 5、配置VRRP组&#xff0c;并加入Active/standby VGMP管…

06-部署knative-eventing

环境要求 For prototyping purposes 单节点的Kubernetes集群&#xff0c;有2个可用的CPU核心&#xff0c;以及4g内存&#xff1b; For production purposes 单节点的Kubernetes集群&#xff0c;需要至少有6个CPU核心、6G内存和30G磁盘空间多节点的Kubernetes集群中&#xff0c;…

Redis设计与实现之慢查询日志

目录 一、慢查询日志 1、相关数据结构 2、慢查询日志的记录 3、慢查询日志的操作 4、如何设置慢查询的阈值&#xff1f; 5、如何查看慢查询日志的内容&#xff1f; 6、如何分析慢查询日志以找出性能瓶颈&#xff1f; 7、如何优化慢查询以提高Redis的性能&#xff1f; 8…

人工智能_机器学习069_SVM支持向量机_网格搜索_交叉验证参数优化_GridSearchCV_找到最优的参数---人工智能工作笔记0109

然后我们再来说一下SVC支持向量机的参数优化,可以看到 这次我们需要,test_data这个是测试数据,容纳后 train_data这个是训练数据 这里首先我们,导出 import numpy as np 导入数学计算包 from sklearn.svm import SVC 导入支持向量机包 分类器包 def read_data(path): wit…

纵横字谜的答案 Crossword Answers

纵横字谜的答案 Crossword Answers - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 翻译后大概是&#xff1a; 有一个 r 行 c 列 (1<r,c<10) 的网格&#xff0c;黑格为 * &#xff0c;每个白格都填有一个字母。如果一个白格的左边相邻位置或者上边相邻位置没有白格&…

【Vue2】Component template should contain exactly one root element.

问题描述 [plugin:vite:vue2] Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead.原因分析 这个错误通常是由于 Vue 组件的模板中包含多个根元素导致的。Vue 要求组件模板中只…

【计算机网络】TCP协议——3. 可靠性策略效率策略

前言 TCP是一种可靠的协议&#xff0c;提供了多种策略来确保数据的可靠性传输。 可靠并不是保证每次发送的数据&#xff0c;对方都一定收到&#xff1b;而是尽最大可能让数据送达目的主机&#xff0c;即使丢包也可以知道丢包。 目录 一. 确认应答和捎带应答机制 二. 超时重…

Linear Regression线性回归(一元、多元)

目录 介绍&#xff1a; 一、一元线性回归 1.1数据处理 1.2建模 二、多元线性回归 2.1数据处理 2.2数据分为训练集和测试集 2.3建模 介绍&#xff1a; 线性回归是一种用于预测数值输出的统计分析方法。它通过建立自变量&#xff08;也称为特征变量&#xff09;和因变…

什么店生意好?C++采集美团商家信息做数据分析

最近遇到几个朋友&#xff0c;想要一起合伙投资一个实体店&#xff0c;不问类型&#xff0c;就看哪类产品相对比较受欢迎。抛除地址位置&#xff0c;租金的影响&#xff0c;我们之谈产品。因此&#xff0c;我熬了几个通宵&#xff0c;写了这么一段爬取美团商家商品信息的数据并…

Linux之grep、sed、awk

目录 1.grep 2.sed 3.awk 1.grep grep 擅长过滤查找&#xff0c;按行进行过滤 例&#xff1a; 当有用户对我们的主机进行爆破攻击时&#xff0c;我们可以使用grep将 ip 查找出来&#xff0c;进行封锁等处理 在 /var/log 目录下的 secure 文件中存放在用户登录连接信息&am…

JVM 垃圾回收详解

前言 什么是垃圾? 垃圾是指运行程序中没有任何引用指向的对象&#xff0c;需要被回收。 内存溢出和内存泄漏 内存溢出&#xff1a;经过垃圾回收之后&#xff0c;内存仍旧无法存储新创建的对象&#xff0c;内存不够溢出。 内存泄漏&#xff1a;又叫“存储泄漏”&#xff0…

Docker与微服务:构建和部署微服务架构的完整指南

微服务架构已经成为现代应用开发的主要范式之一&#xff0c;而Docker容器技术则为微服务的构建、部署和管理提供了理想的解决方案。本文将深入探讨如何使用Docker构建和部署微服务架构&#xff0c;提供更多示例代码和细致的指南&#xff0c;以帮助大家更全面地理解和运用这些关…