迭代器和yield

  2012-08-05©tc庄稼汉

  迭代器是一种方法、get 访问器或运算符,它通过使用 yield 关键字对数组或集合类执行自定义迭代。 yield 返回语句会导致源序列中的元素在访问源序列中的下一个元素之前立即返回给调用方。 尽管您以方法的形式编写迭代器,但编译器会将其转换为一个实际上是状态机的嵌套类。 只要客户端代码中的 foreach 循环继续进行,此类就会跟踪迭代器的位置。

  将使用 foreach 语句从客户端代码中调用迭代器。 例如,您可以为类创建一个迭代器,该迭代器将按相反顺序返回元素,或在迭代器返回元素之前对每个元素执行操作。 在为类或结构创建迭代器时,您不必实现整个 IEnumerator 接口。 当编译器检测到迭代器时,它将自动生成 IEnumerator 或 IEnumerator<T> 接口的 CurrentMoveNextDispose 方法。
一、迭代器概述

  • 迭代器是可以返回相同类型的值的有序序列的一段代码。

  • 迭代器可用作方法、运算符或 get 访问器的代码体。

  • 迭代器代码使用 yield return 语句依次返回每个元素。 yield break 将终止迭代。

  • 可以在类中实现多个迭代器。 每个迭代器都必须像任何类成员一样有唯一的名称,并且可以在 foreach 语句中被客户端代码调用,如下所示:foreach(int x in SampleClass.Iterator2){}

  • 迭代器的返回类型必须为 IEnumerable、IEnumerator、IEnumerable<T> 或 IEnumerator<T>。

  • 迭代器是 LINQ 查询中延迟执行行为的基础。

  yield 关键字用于指定返回的一个或多个值。 到达 yield return 语句时,会保存当前位置。 下次调用迭代器时将从此位置重新开始执行。

  迭代器对集合类特别有用,它提供一种简单的方法来迭代复杂的数据结构(如二进制树)。
二、yield关键字
  

  yield 关键字向编译器指示它所在的方法是迭代器块。 编译器生成一个类来实现迭代器块中表示的行为。 在迭代器块中,yield 关键字与 return 关键字结合使用,向枚举器对象提供值。 这是一个返回值,例如,在 foreach 语句的每一次循环中返回的值。 yield 关键字也可与 break 结合使用,表示迭代结束。 有关迭代器的更多信息,请参见迭代器(C# 编程指南)。

  使用迭代块,编译器会生成一个yield类型,其中包含一个状态机,yield类型执行IEnumerator和IDisposable接口的属性和方法.GetEnumerator()方法实例化并返回一个新的yield类型.在yield类型中,变量state定义了迭代的当前位置,每次调用MoveNext()时,当前位置都会改变.MoveNext()封装了迭代块的代码,设置了current变量的值,使Current属性根据位置返回一个对象。

下面的示例演示两种形式的 yield 语句。
  

yield return <expression>;
yield break;

 

  yield注意事项:  

  在 yield return 语句中,将计算 expression 并将结果以值的形式返回给枚举器对象;expression 必须可以隐式转换为 yield 类型的迭代器。

  在 yield break 语句中,控制权将无条件地返回给迭代器的调用方,该调用方为枚举器对象的 IEnumerator.MoveNext 方法(或其对应的泛型 System.Collections.Generic.IEnumerable<T>)或 Dispose 方法。

  yield 语句只能出现在 iterator 块中,这种块可作为方法、运算符或访问器的主体实现。 这类方法、运算符或访问器的体受以下约束的控制:

  • 不允许不安全块。

  • 方法、运算符或访问器的参数不能是 ref 或 out。

  • yield return 语句不能放在 try-catch 块中的任何位置。 该语句可放在后跟 finally 块的 try 块中。

  • yield break 语句可放在 try 块或 catch 块中,但不能放在 finally 块中。

  yield 语句不能出现在匿名方法中。 有关更多信息,请参见 匿名方法(C# 编程指南)。

  当和 expression 一起使用时,yield return 语句不能出现在 catch 块中或含有一个或多个 catch 子句的 try 块中。 有关更多信息,请参见 异常处理语句(C# 参考)。

三、使用迭代器
  
1.创建迭代器最常用的方法是对 IEnumerable 接口实现 GetEnumerator 方法,例如:

public System.Collections.IEnumerator GetEnumerator()
{for (int i = 0; i < 10; i++){yield return i;}
}

 

  GetEnumerator 方法的存在使得类型成为可枚举的类型,并允许使用 foreach 语句。 如果上面的方法是 ListClass 的类定义的一部分,则可以对该类使用 foreach,如下所示:
  

static void Main()
{ListClass listClass1 = new ListClass();foreach (int i in listClass1){System.Console.Write(i + " ");}// Output: 0 1 2 3 4 5 6 7 8 9
}

 

  foreach 语句调用 ListClass.GetEnumerator() 并使用返回的枚举数来循环访问值。

  2.还可以使用命名的迭代器以支持通过不同的方式循环访问同一数据集合。 例如,您可以提供一个按升序返回元素的迭代器,而提供按降序返回元素的另一个迭代器。 迭代器还可以带有参数,以便允许客户端控制全部或部分迭代行为。 下面的迭代器使用命名的迭代器 SampleIterator 实现 IEnumerable 接口:
  

// Implementing the enumerable pattern
public System.Collections.IEnumerable SampleIterator(int start, int end)
{for (int i = start; i <= end; i++){yield return i;}
}

 

  命名的迭代器的调用方法如下(ps:第一种实现GetEnumerator方法,实际上就是定义一个支持IEnumerable或者IEnumrator的可枚举类型,所以foreach (int i in listClass1),这里的listClass1是listClass类型的实例对象,而下面这个foreach (int n in test.SampleIterator(1, 10))就是使用的迭代器的名称。):
  

ListClass test = new ListClass();foreach (int n in test.SampleIterator(1, 10))
{System.Console.Write(n + " ");
}
// Output: 1 2 3 4 5 6 7 8 9 10

 

  可以在同一个迭代器中使用多个 yield 语句,如下面的示例所示:
  

public System.Collections.IEnumerator GetEnumerator()
{yield return "With an iterator, ";yield return "more than one ";yield return "value can be returned";yield return ".";
}

 

  然后可以使用下面的 foreach 语句输出结果:
  

foreach (string element in new TestClass())
{System.Console.Write(element);
}
// Output: With an iterator, more than one value can be returned.

 

  此示例显示以下文本:

  With an iterator, more than one value can be returned.

  在 foreach 循环的每次后续迭代(或对 IEnumerator.MoveNext 的直接调用)中,下一个迭代器代码体将从前一个 yield 语句之后开始,并继续下一个语句直至到达迭代器体的结尾或遇到 yield break 语句。

  迭代器不支持 IEnumerator.Reset 方法。 若要从头开始重新循环访问,必须获取新迭代器。

转载于:https://www.cnblogs.com/shandong/archive/2012/08/05/2623989.html

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

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

相关文章

中怎样载入选区_ps中快捷大全

使用ps时使用快捷键更方便&#xff0c;操作起来更能提高工作效率&#xff0c;下面给大家总结一下&#xff0c;希望对大家有帮助&#xff0c;当然大家有更好的技巧可以来魔课66网一起交流一下文件设置:Ctrln——新建Ctrlo——打开Ctrlp——打印Ctrls—— 存储Ctrlw——关闭Ctrl …

AspectJ——AOP框架快速入门

一、导包 二、bean.xml配置 三、环绕通知 四&#xff0c;表达式 转载于:https://www.cnblogs.com/wmqiang/p/11617042.html

linux桌面环境应用

为什么80%的码农都做不了架构师&#xff1f;>>> 通常的 Linux 发行版都使用 KDE 或者 GNOME 作为默认的桌面环境。它们都给用户提供了一个原始的并且有吸引力的桌面&#xff0c;并且内置了各式各样的多媒体软件、系统程序、游戏、实用程序、网页开发工具、编程 工具…

[转]C++的坑真的多吗?

http://coolshell.cn/articles/7992.html#jtss-tsina 先说明一下&#xff0c;我不希望本文变成语言争论贴。希望下面的文章能让我们客观理性地了解C这个语言。&#xff08;另&#xff0c;我觉得技术争论不要停留在非黑即白的二元价值观上&#xff0c;这样争论无非就是比谁的嗓门…

python3.5安装scrapy_Python3.5下安装测试Scrapy

1、引言Scrapy框架结构清晰&#xff0c;基于twisted的异步架构可以充分利用计算机资源&#xff0c;是做爬虫必备基础&#xff0c;本文将对Scrapy的安装作介绍。2、安装lxml2.1 下载地址&#xff1a;https://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted  选择对应python3.5…

MMC无法创建管理单元

解决方法&#xff1a;经过我多方考证&#xff0c;原来只是一个小小的问题。那就是”环境变量”在作怪 1. 右键单击“我的电脑”&#xff0c;然后单击“属性”。 2. 在“高级”选项卡上&#xff0c;单击“环境变量”。 3. 在“系统变量”下&#xff0c;双击“PATH 环境变量”。…

第一个Sprint冲刺第六天

讨论成员&#xff1a;邵家文、李新、朱浩龙、陈俊金 讨论问题&#xff1a;解决编写代码的问题 讨论地点&#xff1a;宿舍 进展&#xff1a;已开始对代码的编写 转载于:https://www.cnblogs.com/shaojiawen/p/4970305.html

AspectJ基于xml和基于注解

一、基于xml 执行的切入点中具体方法有返回值&#xff0c;则方法结束会立即执行后置通知&#xff0c;然后再执行环绕通知的放行之后的代码&#xff1b; 2、连接点即所有可能的方法&#xff0c;切入点是正真被切的方法&#xff0c;连接点方法名&#xff1a; 其中&#xff0c;只有…

C++之private虚函数

一般我们说虚函数&#xff0c;它的访问级别都是public的&#xff0c;用类对象可以直接调用&#xff0c;这样就可以实现运行时的类型绑定&#xff0c;那如果我们将虚函数私有化会出现什么情况呢&#xff1f; 我们先来看一个非虚函数私有化的例子 class Base { private:void Prin…

M| SQL 导入导出的时候数据库表的主键和自动编号丢失 怎么办

--导入数据时&#xff0c;使用默认选项&#xff0c;会丢失主键、约束、默认值等属性&#xff0c;按如下步骤操作&#xff1a; --> 导出向导 --> 选择数据源 --> 选择目的 --> 指定表复制或查询&#xff1a;不要使用默认选项&#xff0c;选择“在…

设置堆内存大小_jmap和jhat命令行工具的配合使用,更好的掌握堆内存状况

Java的内存映像工具&#xff0c;jmap&#xff0c;Memory Map for Java&#xff0c;用于生成堆转储快照&#xff0c;一般成为heapdump或者dump文件&#xff0c;出了获取dump文件&#xff0c;这个工具还可以查询finalize执行队列&#xff0c;Java堆和永久代的详细信息&#xff0c…

MT-Retina.js

MT-Retina.js Github: MT-Retina.js serve high-resolution images to devices with retina displays. 之前月大总管写的为高分屏提供不同分辨率图像支持的插件&#xff0c;需求变动&#xff0c;增加了语言支持。 Usage add lib & config <script src"dist/retina.…

不同情况通知执行的顺序

1.service方法有返回值 无异常 XML ***************************************1.前置通知...deleteUser2.环绕通知...开启事务...deleteUser通过id删除用户3.后置通知...deleteUser返回值:14.环绕通知....提交事务...最终通知...deleteUser**********************************…

sessionState 配置方案

配置SQL Server Session方法 以下过程是在Win 2003 SP2 IIS 6.0, ASP.NET 2.0, SQL Server 2005下进行的。 1. 安装Session数据库 到Framework目录 C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727运行下面的命令: aspnet_regsql.exe -ssadd -sstype c -d [DB] -S [Server] …

Open*** 服务器的搭建

服务介绍直译就是虚拟专用通道&#xff0c;是提供给企业之间或者个人与公司之间安全数据传输的隧道&#xff0c;Open无疑是Linux下开源的先锋&#xff0c;提供了良好的性能和友好的用户GUI。它大量使用了OpenSSL加密库中的SSLv3/TLSv1协议函数库。实验拓扑图实验环境xuegod 63 …

怎么批量选择目标_全日制专升本一次可以报几个学校?目标院校应该怎么选择?...

很多普通专升本考生们在备考的时候会对报考环节存在疑问&#xff0c;比如&#xff0c;普通专升本可以报几个学校&#xff1f;报考院校怎么选择&#xff1f;下面我们就这两个问题进行解答。想要知道湖北普通专升本考试一次可以报几个院校和专业&#xff0c;我们不妨先来看看《省…

jdbcTemplate快速入门

一、 c3p0和dbcp区别 二、导包 hibernate通过映射自动创建表&#xff1b; 三、代码实现 转载于:https://www.cnblogs.com/wmqiang/p/11617387.html

使用SecureCrt远程登录Linux安装配置教程

1. 首先验证安装secureCRT的本地机和linux服务器能否ping的通&#xff1b; 2. 判断linux 服务端是否安装了ssh 若未安装的话&#xff1a; apt-get installopenssh-server 3. 备份sshd_config&#xff1a; sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.originalsudo chm…

VS-c# web程序:gridview保存Excel文件遇到的问题

1。Gridview1必须放在具有runatserver的窗体标记内 解决方法&#xff1a;在程序相应位置加上以下代码中绿色部分代码即可。 //按钮点击事件 protected void Button1_Click(object sender, EventArgs e) { Response.Clear(); DownloadExcelFla…

云服务器镜像麻烦吗_简单说说云服务器的镜像功能作用

不少小伙伴在创建云服务器的时候会看到镜像这个功能而且需要操作到&#xff0c;但是镜像的具体作用是什么完全不清楚&#xff0c;今天小编就带大家来简单了解一下。镜像是通过云服务器下的磁盘创建的副本文件&#xff0c;该文件包含了一块或多块磁盘的所有数据集合&#xff0c;…