什么时候可以使用yield的关键字来定义迭代器?

  • 迭代器的返回类型必须是IEnumerable、IEnumerable<T>、IEnumerator 或 IEnumerator<T>
  • 迭代器的入参不能包括ref或out类型的参数

首先,我们定义一个简单的遍历。

  1. static void Main(string[] args)
  2. {
  3. List<Person> persons = new List<Person>();
  4. persons.Add(new Person { SaySome = "Hello World,I am Sheldon" });
  5. persons.Add(new Person { SaySome = "Hello World,I am Penny" });
  6. persons.Add(new Person { SaySome = "Hello World,I am Amy" });
  7. foreach (var item in persons)
  8. {
  9. Console.WriteLine(item.SaySome);
  10. }
  11. }

它的输出结果:

接下来,我们使用yield,来实现同样的效果。

  1. static void Main(string[] args)
  2. {
  3. foreach (var item in GetEnumerator())
  4. {
  5. Console.WriteLine(item.SaySome);
  6. }
  7. }
  8.  
  9. public static IEnumerable<Person> GetEnumerator()
  10. {
  11. yield return new Person { SaySome = "Hello World,I am Sheldon" };
  12. yield return new Person { SaySome = "Hello World,I am Penny" };
  13. yield return new Person { SaySome = "Hello World,I am Amy" };
  14. }

虽然,我们得到了同样的结果,但是yield到底是如何做到的?

(又是翻书,又是看msdn,终于得到了答案)

使用yield语句时,它会自动生成一个枚举器,而不是仅仅生成一个包含项的列表。

——————————————————    以上内容关于yield描述了大概    ———————————————————————

——————————————————以下内容主要说明foreach如何迭代———————————————————————

这个枚举器通过foreach调用,foreach中依次访问每一项时,就会访问这个枚举器,从而达到迭代大量数据,而无须一次把所有的数据写到内存中。

关于枚举器,我查看了system.collection.generic空间下的源码。

为了知道foreach中是如何通过枚举器来工作的。

我们来根据上面的List集合声明一个简单的枚举器

(这个枚举器,只是为了简单的说明一下问题)

  1. public class GameMoves
  2. {
  3. private IEnumerator cross;
  4. private IEnumerator circle;
  5. public GameMoves()
  6. {
  7. cross = Cross();
  8. circle = Circle();
  9. }
  10. private int move = ;
  11. const int MaxMoves = ;
  12. public IEnumerator Cross()
  13. {
  14. while (true)
  15. {
  16. Console.WriteLine("Cross, move {0}", move);
  17. if (++move >= MaxMoves)
  18. {
  19. yield break;
  20. }
  21. yield return circle;
  22. }
  23. }
  24. public IEnumerator Circle()
  25. {
  26. while (true)
  27. {
  28. Console.WriteLine("Circle,move{0}",move);
  29. if (++move>=MaxMoves)
  30. {
  31. yield break;
  32. }
  33. yield return cross;
  34. }
  35. }
  36. }

重写一下Main方法

  1. var game = new GameMoves();
  2. //将枚举器设置为由game.Cross()返回的枚举器类型
  3. IEnumerator enumerator = game.Cross();
  4. //第一次调用 MoveNext()时,会调用Cross()方法,Cross()方法使用yield返回另一个枚举器
  5. while (enumerator.MoveNext())
  6. {
  7. //返回的值可以用Current属性访问,并设置为enumerator变量,用于下一次循环
  8. enumerator = enumerator.Current as IEnumerator;
  9. }

通过上面的例子我们能看出使用while来变向说明foreach的内部执行方式。

通过 foreach 语句或 LINQ 查询来使用迭代器方法。

foreach 循环的每次迭代都会调用迭代器方法。 迭代器方法运行到 yield return 语句时,会返回一个 expression,并保留当前在代码中的位置。 下次调用迭代器函数时,将从该位置重新开始执行。

(部分源自msdn)

C#基础知识 yield与foreach的更多相关文章

  1. C#基础知识---迭代器与Foreach语句

    一.Foreach语句简介 在C# 1.0中我们经常使用foreach来遍历一个集合中的元素,然而如果一个集合要支持使用foreach语句来进行遍历,这个集合一般需要IEnumerable或IEnum ...

  2. C# 基础知识总结

    要学好C#,基础知识的重要性不言而喻,现将常用到的一些基础进行总结,总结如下: 1. 数据类型转换: 强制类型转换(Chart--> int):  char cr='A';   int i = ...

  3. Java 基础知识总结

    作者QQ:1095737364    QQ群:123300273     欢迎加入! 1.数据类型:  数据类型:1>.基本数据类型:1).数值型: 1}.整型类型(byte  8位   (by ...

  4. Java基础知识总结(超级经典)

    Java基础知识总结(超级经典) 写代码: 1,明确需求.我要做什么? 2,分析思路.我要怎么做?1,2,3. 3,确定步骤.每一个思路部分用到哪些语句,方法,和对象. 4,代码实现.用具体的java ...

  5. 毕向东—Java基础知识总结(超级经典)

    Java基础知识总结(超级经典) 写代码: 1,明确需求.我要做什么? 2,分析思路.我要怎么做?1,2,3. 3,确定步骤.每一个思路部分用到哪些语句,方法,和对象. 4,代码实现.用具体的java ...

  6. C#基础知识汇总(不断更新中)

    ------------------------------目录---------------------------- 1.隐式类型2.匿名类型3.自动属性4.初始化器5.委托6.泛型7.泛型委托8 ...

  7. Java 基础知识总结1

    作者QQ:1095737364    QQ群:123300273     欢迎加入! 1.数据类型:  数据类型:1>.基本数据类型:1).数值型: 1}.整型类型(byte  8位   (by ...

  8. Linq的简介和基础知识学习

    学习LINQ之前,我们要知道LINQ是干什么,解决什么问题的,怎样学习? 一.LINQ简介 1.什么是LINQ? 什么是LINQ?LINQ中文翻译为语言集成查询(Language Integrated ...

  9. 黑马毕向东Java基础知识总结

    Java基础知识总结(超级经典) 转自:百度文库 黑马毕向东JAVA基础总结笔记    侵删! 写代码: 1,明确需求.我要做什么? 2,分析思路.我要怎么做?1,2,3. 3,确定步骤.每一个思路部 ...

随机推荐

  1. PHP--最常用--必背函数总结!php学习者收藏必备!

    一.PHP系统函数 函数 功能 用法 var_dump() 打印变量结构信息,包括类型和值.数组将递归展开值 var_dump ( $arg1...); echo():是语法结构 输出一个或者多个字符 ...

  2. Appscan 配置中登录管理的问题

    一.登录录制时录制为空 这个问题出现在 9.0.3.5 版本上,当时同事一录制为空,我录制却ok,后来发现他录制前将谷歌浏览是打开状态,谷歌浏览关闭掉,再使用外部浏览器Chrome进行会话录制后,问题 ...

  3. Javascript parseFloat、parseDouble类型转换,数值加减,四舍五入

    <script language="JavaScript">var a = "0.11";var b = "0.2801";va ...

  4. Mybatis框架的搭建和基本使用方法

    1.1MyBatis的下载 最新yBatis可以在github官网上下载: https://github.com/mybatis/mybatis-3 1.2 Mybatis Jar包 1.3MyBat ...

  5. 聊下 git 多账户问题

    git 多账户问题 标签(空格分隔):git github gitlab git多账户 背景 git 多账号配置 ssh 多密钥对配置 背景 在使用 git 的时候我们都会面临多账户问题,比较常见的就 ...

  6. Vue.js—实现图书管理系统

      前  言 今天我们主要一起来学习一个新框架的使用--Vue.js,之前我们也讲过AngularJS是如何使用的,而今天要讲的Vue.js的语法和AngularJS很相似,因为 AngularJS ...

  7. org.hibernate.validator.constraints.NotBlank' validating type 'java.lang.Integer

    使用hibernate时,在save方法时,报了:org.hibernate.validator.constraints.NotBlank' validating type 'java.lang.In ...

  8. Pyhton编程(六)之基本数据类型-集合(补充)

    集合(set) 集合其实就是一个无序的,自动去重的数据集合,它主要的作用是用来去重和进行关系测试,集合的定义方法如下: name=set("czp") /name=set({1,2 ...

  9. Vue-Access-Control:前端用户权限控制解决方案

    原文地址:http://refined-x.com/2017/11/28/Vue2.0用户权限控制解决方案/ Vue-Access-Control是一套基于Vue/Vue-Router/axios 实 ...

  10. 【二十二】mysqli事务处理

    事务处理 事务基本原理 如果不开启事务,执行一条sql,马上会持久化数据.可见:默认的mysql对sql语句的执行是自动提交的! 如果开启了事务,就是关闭了自动提交的功能,改成了commit执行自动提 ...