C#-14 枚举器和迭代器
一 枚举器和可枚举类型
当我们为数组使用foreach语句时,这个语句为我们依次取出了数组中的每一个元素。
var arrInt = new int[] { 11, 12, 13, 14 };
foreach (var item in arrInt)
{
Console.WriteLine(item);
}
原因是数组实现了IEnumerable接口,接口提供了一个GetEnumerator方法可以获取一个实现了IEnumerator接口的枚举器对象。
枚举器可以依次返回请求的数组中的元素。
实现了IEnumerable接口类型叫做可枚举类型。数组是可枚举类型。
public interface IEnumerable
{
// 摘要: 返回循环访问集合的枚举器。
// 返回结果:一个可用于循环访问集合的 System.Collections.IEnumerator 对象。
IEnumerator GetEnumerator();
}
foreach语句设计用来和可枚举类型一起使用。只要给它的遍历对象是可枚举类型,它就会执行如下行为:
- 通过调用GetEnumerator方法获取对象的枚举器;
- 从枚举器中请求每一项并把它作为迭代变量。
二 IEnumerator接口
IEnumerator接口的定义如下:
public interface IEnumerator
{
// 摘要:获取集合中位于枚举数当前位置的元素
// 返回结果:集合中位于枚举数当前位置的元素。
object Current { get; }
// 摘要:将枚举数推进到集合的下一个元素。
// 返回结果:如果枚举数已成功地推进到下一个元素,则为 true;如果枚举数传递到集合的末尾,则为 false。
// 异常:T:System.InvalidOperationException:创建枚举器后,已修改该集合。
bool MoveNext(); // 摘要:将枚举数设置为其初始位置,该位置位于集合中第一个元素之前。
// 异常: T:System.InvalidOperationException: 创建枚举器后,已修改该集合。
void Reset();
}
有了枚举器,就可以使用MoveNext和Current来模仿foreach循环:
int[] arrInt = new int[] { 11, 12, 13, 14 };
foreach (var item in arrInt)
{
Console.WriteLine(item);
}
var enumerator = arrInt.GetEnumerator();
while (enumerator.MoveNext())
{
var item = (int)enumerator.Current;
Console.WriteLine(item);
}
下面是一个使用IEnumerator和IEnumerable的小例子:

class Program
{
static void Main(string[] args)
{
var myColor = new MyColors();
foreach (var item in myColor)
{
Console.WriteLine(item);
}
}
} class ColorEnumeraotr : IEnumerator
{
string[] _colors;
int _position = -1; public ColorEnumeraotr(string[] theColors)
{
_colors = new string[theColors.Length];
for (int i = 0; i < theColors.Length; i++)
{
_colors[i] = theColors[i];
}
} public object Current
{
get
{
if (_position == -1)
throw new InvalidOperationException();
if (_position >= _colors.Length)
throw new InvalidOperationException(); return _colors[_position];
}
} public bool MoveNext()
{
if (_position < _colors.Length - 1)
{
_position++;
return true;
}
return false;
} public void Reset()
{
_position = -1;
}
} class MyColors : IEnumerable
{
string[] Colors = new string[] { "red","blue","yellow","green","white"}; public IEnumerator GetEnumerator()
{
return new ColorEnumeraotr(Colors);
}
}
三 泛型枚举接口
非泛型接口的实现不是类型安全的,它返回object的引用,然后必须转化为实际类型。
所以实际上,在多数情况下,我们应该使用泛型版本的IEnumerable<T>和IEnumerator<T>。
泛型接口的枚举器是类型安全的,它返回实际类型的引用。
IEnumerable<T>接口的GetEnumerator方法返回实现IEnumerator<T>的枚举器对象。
实现IEnumerator<T>的枚举器类的Current属性,它返回T类型的对象。
四 迭代器
C#从2.0版本开始提供了更简单的创建枚举器和可枚举类型的方式。这种结构叫做迭代器。
迭代器块是有一个或多个yield语句的代码块。
迭代器块与其他代码块不同。其他块包含的语句是命令式的,也就是块中的语句依次执行,最后离开块。
而迭代器块是描述了希望编译器为我们创建的枚举器类的行为,迭代器块中的代码描述了如何枚举元素。
迭代器块有两个特殊语句:
- yield return : 指定了序列中返回的下一项;
- yield break : 指定在序列中没有其他项。
//产生枚举器的迭代器
public IEnumerator<string> IteratorMethod1()
{
yield return "red";
yield return "blue";
yield return "yellow";
} //产生可枚举类型的迭代器
public IEnumerable<string> IteratorMethod2()
{
yield return "red";
yield return "blue";
yield return "yellow";
}
4.1 使用迭代器来创建枚举器
下面代码演示如何使用迭代器来创建枚举器:

class Program
{
static void Main(string[] args)
{
var mc = new MyClass();
foreach (var item in mc)
{
Console.WriteLine(item);
}
}
} class MyClass
{
public IEnumerator<string> GetEnumerator()
{
return MyEnumerator(); //返回枚举器
} //迭代器
public IEnumerator<string> MyEnumerator()
{
yield return "red";
yield return "blue";
yield return "yellow";
}
}
4.2 使用迭代器来创建可枚举类型
下面代码演示如何使用迭代器来创建可枚举类型:

class Program
{
static void Main(string[] args)
{
var mc = new MyClass();
foreach (var item in mc)
{
Console.WriteLine(item);
} foreach (var item in mc.MyEnumerable())
{
Console.WriteLine(item);
}
}
} class MyClass
{
public IEnumerator<string> GetEnumerator()
{
IEnumerable<string> myEnumerable = MyEnumerable();
return myEnumerable.GetEnumerator();
} public IEnumerable<string> MyEnumerable()
{
yield return "red";
yield return "blue";
yield return "yellow";
}
}
C#-14 枚举器和迭代器的更多相关文章
- C#图解教程 第十八章 枚举器和迭代器
枚举器和迭代器 枚举器和可枚举类型 foreach语句 IEnumerator接口 使用IEnumerable和IEnumerator的示例 泛型枚举接口迭代器 迭代器块使用迭代器来创建枚举器使用迭代 ...
- C# 枚举器和迭代器
一.枚举器(enumerator)和可枚举类型(enumeration) 我们都知道foreach语句可以用来遍历数组中的元素,但你有没有想过为什么它可以被foreach处理呢? 这是因为数组可以按需 ...
- 设计模式 - 适配器模式(adapter pattern) 枚举器和迭代器 具体解释
适配器模式(adapter pattern) 枚举器和迭代器 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考适配器模式(adapter patter ...
- C#知识点-枚举器和迭代器
一.几个基本概念的理解 问题一:为什么数组可以使用foreach输出各元素 答:数组是可枚举类型,它实现了一个枚举器(enumerator)对象:枚举器知道各元素的次序并跟踪它们的位置,然后返回请求的 ...
- 【Unity|C#】基础篇(20)——枚举器与迭代器(IEnumerable/IEnumerator)
[学习资料] <C#图解教程>(第18章):https://www.cnblogs.com/moonache/p/7687551.html 电子书下载:https://pan.baidu. ...
- C#枚举器/迭代器
一.枚举器 1.为什么foreach可以顺序遍历数组? 因为foreach可以识别可枚举类型,通过访问数组提供的枚举器对象来识别数组中元素的位置从而获取元素的值并打印出来. 2.什么是枚举器?可枚举类 ...
- C#中的枚举器(转)
术语表 Iterator:枚举器(迭代器) 如果你正在创建一个表现和行为都类似于集合的类,允许类的用户使用foreach语句对集合中的成员进行枚举将会是很方便的.这在C# 2.0中比 C# 1.1更容 ...
- 【转】C#学习之用迭代器实现枚举器
http://www.cnblogs.com/zouzf/archive/2012/02/22/2362954.html 本人初学C#,本文仅供个人整理思路用,那里说得不对,请大家多多指教,万分感激! ...
- ruby迭代器枚举器
迭代器一个迭代器是一个方法,这个方法里面有yield语句,使用了yield的方法叫做迭代器,迭代器并非一定要迭代,与传递给这个方法的块进行数据传输 yield将数据传给代码快,代码块再把数据传输给yi ...
随机推荐
- 【一本通提高树链剖分】「ZJOI2008」树的统计
[ZJOI2008]树的统计 题目描述 一棵树上有 n n n 个节点,编号分别为 1 1 1 到 n n n,每个节点都有一个权值 w w w. 我们将以下面的形式来要求你对这棵树完成一些操作: I ...
- 基于CentOS的IB网卡驱动安装
一.准备步骤 1.查看centos版本 cat /etc/issue或者cat /etc/redhat-release 2.查看linux版本 cat /proc/version或uname -a或 ...
- 关于微信小程序生产环境体验版获取不到openId的问题(大坑)
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_119 我们知道openid是微信用户验证的重要标识,支付功能严重依赖这个东西,之前我们做微信支付的时候是通过在微信客户端直接调用官 ...
- 记一次 .NET 某工控自动化控制系统 卡死分析
一:背景 1. 讲故事 前段时间遇到了好几起关于窗体程序的 进程加载锁 引发的 程序卡死 和 线程暴涨 问题,这种 dump 分析难度较大,主要涉及到 Windows操作系统 和 C++ 的基础知识, ...
- 【web自动化测试】playwright安装失败怎么办
在安装中,如果没有输入 playwright install, 则不会安装浏览器,运行 playwright codegen 时会报浏览器找不到的错误: "chromium" br ...
- CSS3 基础学习
CSS基础学习 当前进度[P78] 参考资料 视频链接:https://www.bilibili.com/video/BV14J4114768 菜鸟教程:https://www.runoob.com/ ...
- 技术分享 | Prometheus+Grafana监控MySQL浅析
GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 简介 Prometheus 一套开源的监控&报警&时间序列数据库的组合,通常 Kubernetes 中都会 ...
- 活动回顾丨ALC Beijing 首场 Meetup:《开源到底有多难?》
8月16日,ALC Beijing 的首次线下沙龙活动 -- <开源到底有多难?>在微软大厦如期举行.本次沙龙主要是分享开源开发经验.探讨如何让开源项目更加茁壮成长,以及分享 ASF 管理 ...
- HCIA-Datacom 3.3 实验三:以太网链路聚合实验
实验介绍 随着网络规模不断扩大,用户对骨干链路的带宽和可靠性提出越来越高的要求.在传统技术中,常用更换高速率的接口板或更换支持高速率接口板的设备的方式来增加带宽,但这种方案需要付出高额的费用,而且不够 ...
- 痞子衡嵌入式:MCUXpresso IDE下设置代码编译优化等级的几种方法
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是MCUXpresso IDE下设置代码编译优化等级的几种方法. 最近公司芯片设计团队正在开发一款全新的基于 Cortex-M33 内核的 ...