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 ...
随机推荐
- 利用Kaptcha.jar生成图片验证码(以下源码可以直接复制并自定义修改)
说明:Kaptcha是一个很实用的验证码生成工具,它可以生成各种样式的验证码,因为它是可以配置的 目录: 一 实现步骤 二 实例 A 编写jsp页面 B 配置web.xml C 验证输入正确与否. 一 ...
- python 日志类
简介 在所有项目中必不可少的一定是日志记录系统,python为我们提供了一个比较方便的日志模块logging,通常,我们都会基于此模块编写一个日志记录类,方便将项目中的日志记录到文件中. loggin ...
- 【Java线程池】 java.util.concurrent.ThreadPoolExecutor 分析
线程池概述 线程池,是指管理一组同构工作线程的资源池. 线程池在工作队列(Work Queue)中保存了所有等待执行的任务.工作者线程(Work Thread)会从工作队列中获取一个任务并执行,然后返 ...
- linux学习随笔2之防火墙
centos7默认使用的防火墙是firewalld 查看所有打开的端口: firewall-cmd --zone=public --list-ports 更新防火墙规则: firewall-cmd - ...
- 9. 利用Docker快速构建MGR | 深入浅出MGR
目录 1.安装Docker 2.拉取GreatSQL镜像,并创建容器 2.1 拉取镜像 2.2 创建新容器 2.3 容器管理 3.构建MGR集群 3.1 创建专用子网 3.2 创建3个新容器 3.3 ...
- 万答#4,延迟从库加上MASTER_DELAY,主库宕机后如何快速恢复服务
欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 当主库宕机后,延迟从库如何才能"取消"主动延迟,以便恢复服务 ...
- 老板加薪!看我做的WPF Loading!!!
老板加薪!看我做的WPF Loading!!! 控件名:RingLoading 作者:WPFDevelopersOrg 原文链接: https://github.com/WPFDevelopersOr ...
- 构建数据湖上低延迟数据 Pipeline 的实践
T 摘要 · 云原生与数据湖是当今大数据领域最热的 2 个话题,本文着重从为什么传统数仓 无法满足业务需求? 为何需要建设数据湖?数据湖整体技术架构.Apache Hudi 存储模式与视图.如何解决冷 ...
- MySQL8.0解决“MySQL 服务无法启动。 服务没有报告任何错误。”
TL;NRs 初始化服务时最好使用mysqld --initialized --console命令: MySQL8.0的配置变量与MySQL5.7不同,[mysqld]下面设置字符集的变量名为char ...
- Luogu1063 能量项链 (区间DP)
惊恐地发现自己连区间DP都会错2333 #include <iostream> #include <cstdio> #include <cstring> #incl ...