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 ...
随机推荐
- Hbase学习(三)过滤器 java API
Hbase学习(三)过滤器 HBase 的基本 API,包括增.删.改.查等. 增.删都是相对简单的操作,与传统的 RDBMS 相比,这里的查询操作略显苍白,只能根据特性的行键进行查询(Get)或者根 ...
- kubernetes 静态存储与动态存储
静态存储 Kubernetes 同样将操作系统和 Docker 的 Volume 概念延续了下来,并且对其进一步细化.Kubernetes 将 Volume 分为持久化的 PersistentVo ...
- springmvc源码笔记-HandlerMapping注入
在springmvc中,如何根据url找到controller以及对应方法,依赖的是HandlerMapping接口的getHandler方法 在spring容器中默认注册的HandlerMappin ...
- Windows 安装 Linux 环境
简介 在实际开发中,我们除了在Windows上进行开发外,可能还需要基于Linux进行一些编译或者测试等,因此,我们可能需要在Windows环境中安装Linux环境,通常可能我们会使用虚拟机替代,但是 ...
- 使用gulp助力前端自动化
前言 随着前端诸如webpack,rollup,vite的发展,gulp感觉似乎好像被取代了.其实并没有,只不过它从台前退居到了幕后.我们仍然可以在很多项目中看到它的身影,比如elementplus. ...
- JavaWeb--基本概念、Web服务器与Tomcat
前言 Java Web 其实就是一个技术的总和,把Web看成一个容器而已主要使用JavaEE技术来实现.在加上各种中间件. 整个javaWeb阶段的内容通过实际的案例贯穿学习, 所涉及到的技术知识点会 ...
- .NET 6学习笔记(4)——解决VS2022中Nullable警告
很多小伙伴在升级到Visual Studio 2022后发现,如果我们去新建一个.NET 6的项目,和原先VS2019中一摸一样的写法,却会出现CS8618 Non-nullable property ...
- 【Maui正式版】创建可跨平台的Maui程序,以及有关依赖注入、MVVM双向绑定的实现和演示
前言:Maui终于在昨天(2022年8月9日)推送出来了.今儿就迫不及待来把玩一下先. A.我本地已有VS2022,不过版本比较老,此处选择更新.工具 -> 获取功能和更新里面,可以获取到新版本 ...
- Nginx 代理Vue项目出现Invalid Host header
说明 使用 Nginx 的 upstream 对 Vue 项目做负载均衡时,代理的地址无法访问目标地址,且页面报错: Invalid Host header(无效主机头) 分析 检查 Nginx 的 ...
- Unity获取脚本的CustomEditor(自定义编辑)数据
在此之前,粗略的介绍下 CustomEditor(自定义编辑). Unity对于我们创建的Mono脚本提供了属性面板的展示和修改.默认情况下,Inspector面板中会显示当前脚本类的公开字段(pub ...