C#yield return和yield break
C#yield return和yield break
晚上好,各位。今天结合书中所讲和MSDN所查,聊下yield关键字,它是我们简化迭代器的关键。
如果你在语句中使用了yield关键字,则意味着它在其中出现的方法、运算符或get访问器是迭代器,通过使用yield定义迭代器,可在实现自定义集合类型的IEnumerable和IEnumerator模式时无需显示类(保留枚举状态类),使用yield有两种形式,如下
- 1 yield return 表达式
- 2 yield break
先说明一下yield return语句,每一次返回一个元素。通过foreach语句或LINQ查询来使用迭代器方法。foreach循环的每次迭代都会调用迭代器方法,会保存当前返回的状态。

- 1 static void Main(string[] args)
- 2 {
- 3 foreach (int i in GetValues())
- 4 {
- 5 Console.WriteLine(i);
- 6 }
- 7 Console.ReadKey();
- 8 }
- 9
- 10 static IEnumerable<int> GetValues()
- 11 {
- 12 yield return 1;
- 13 yield return 2;
- 14 yield return 3;
- 15 }

不能将yield return语句放在try-catch之中,但可以把它放在try-finally之中。yield return有两个特点:1.返回类型必须是IEnumerable、IEnumerator、IEnumerator<T>、IEnumerable<T>.2.不能使用ref和out修饰符。在匿名方法和不安全代码中不能包含yield return和yield break。下面我们使用yield return来简化上一篇中对Student的迭代,重新个性了Queue<T>这个泛型类,如下

- 1 class Queue<T> : IEnumerable<T> where T : class
- 2 {
- 3 public List<T> objects = new List<T>();
- 4 int startPoint = 0;
- 5 public Queue(List<T> list)
- 6 {
- 7 objects = list;
- 8 }
- 9
- 10 //实现从IEnumerable中的GetEnumerator方法
- 11 /*
- 12 个人觉得这个方法在迭代中只会调用一次,不然每次都返回一个新的QueueIterator<T>对象,位置记录都会重置为-1
- 13 */
- 14 public IEnumerator<T> GetEnumerator()
- 15 {
- 16 //return new QueueIterator<T>(this);
- 17 for (int index = 0; index < objects.Count; index++)
- 18 {
- 19
- 20 yield return objects[(index + startPoint) % objects.Count];
- 21 }
- 22 }
- 23
- 24 IEnumerator IEnumerable.GetEnumerator()
- 25 {
- 26 throw new NotImplementedException();
- 27 }
- 28 }

代码到了yield return时,返回objects中一个合适的元素,并保存当前的状态,等下一次调用时从记数的位置开始。在使用程序中,如下,和原先一样。

- 1 List<Student> list = new List<Student> {
- 2 new Student("СA"),
- 3 new Student("СB"),
- 4 new Student("СC"),
- 5 new Student("СD"),
- 6 new Student("СE")
- 7 };
- 8 ConsoleDemo.Chapter6.Queue<Student> lq = new Chapter6.Queue<Student>(list);
- 9
- 10 foreach (var obj in lq)
- 11 {
- 12 obj.SayName();
- 13 }

可以看到结果都是迭代的打印每一个元素的名字。在来说下return break,从break中可以看中,是跳出,那意思就应该上跳出迭代,如

- 1 class Program
- 2 {
- 3 static void Main(string[] args)
- 4 {
- 5
- 6 foreach (int i in GetValues())
- 7 {
- 8 Console.WriteLine(i);
- 9 }
- 10 Console.ReadKey();
- 11 }
- 12
- 13 static IEnumerable<int> GetValues()
- 14 {
- 15 yield return 1;
- 16 yield return 2;
- 17 yield break;
- 18 yield return 3;
- 19 }
- 20 }

到了yield return 2时,下一语句是yield break,则在控制台只会打印1,2,因为在打印3之前就使用yield break跳出迭代了。
下面我们使用一个实际点的读文件的例子。新建一个文本demo.txt,内容如下

- 1 1
- 2 2
- 3 3
- 4 4
- 5 5
- 6 6
- 7 7
- 8 8
- 9 9
- 10 0

代码如下

- 1 class Program
- 2 {
- 3 static void Main(string[] args)
- 4 {
- 5 foreach(var line in ReadLines("./demo.txt"))
- 6 {
- 7 Console.WriteLine(line);
- 8 }
- 9 Console.ReadKey();
- 10 }
- 11
- 12 static IEnumerable<string> ReadLines(string path)
- 13 {
- 14 string line;
- 15 TextReader tr = File.OpenText(path);
- 16 while ((line = tr.ReadLine()) != null)
- 17 {
- 18 yield return line;
- 19 }
- 20 }
- 21 }

当然其实File中的表态方法是有ReadLines方法的,返回的也是IEnumerable<string>,看来我们是多此一举了,不过也不错,知道了一些yield的使用,原理的那些真心不敢写,写了自己也看不懂,希望以后能用自己组织语言,解译那些原理。
请斧正。
C#yield return和yield break的更多相关文章
- 12.C#yield return和yield break及实际应用小例(六章6.2-6.4)
晚上好,各位.今天结合书中所讲和MSDN所查,聊下yield关键字,它是我们简化迭代器的关键. 如果你在语句中使用了yield关键字,则意味着它在其中出现的方法.运算符或get访问器是迭代器,通过使用 ...
- yield return 和 yield break
//yield return 返回类型必须为 IEnumerable.IEnumerable<T>.IEnumerator 或 IEnumerator<T>. static I ...
- yield return 和yield break
这个还是有点意思,两个都是有返回的意思,但是区别在哪里呢? 1.return 会销毁函数的局部变量,下次调用的时候又会产生新的值 2.yield 当退出函数的时候,变量人然存在,函数下次调用的时候变量 ...
- C# yield return 和 yield break
yield关键字用于遍历循环中,yield return用于返回IEnumerable<T>,yield break用于终止循环遍历. 以下对比了使用yield return与不使用yie ...
- 读书笔记 C# yield return与yield break执行顺序的浅析
yield return可一次返回一个元素,并保留当前在代码中的位置,下次调用当前迭代器函数时,将从该位置从新执行.也就是说执行了yield return的时候,迭代器函数就返回了一个元素给forea ...
- yield return,yield break
转自, http://www.cnblogs.com/kingcat/archive/2012/07/11/2585943.html yield return 表示在迭代中下一个迭代时返回的数据,除此 ...
- 可惜Java中没有yield return
项目中一个消息推送需求,推送的用户数几百万,用户清单很简单就是一个txt文件,是由hadoop计算出来的.格式大概如下: uid caller 123456 12345678901 789101 12 ...
- yield return的用法简介
使用yield return 语句可一次返回一个元素. 迭代器的声明必须满足以下要求: 返回类型必须为 IEnumerable.IEnumerable<T>.IEnumerator 或 I ...
- C#中yield return用法分析
这篇文章主要介绍了C#中yield return用法,对比使用yield return与不使用yield return的流程,更直观的分析了yield return的用法,需要的朋友可以参考下. 本文 ...
随机推荐
- C++四种类型的转换
在C/C++使用的语言 (type) value(您还可以使用type(value))对于显式类型转换,经常提到投.转换程序猿的精度等完全掌握手,一个传统投往往是过度使用.成为C++要根源. 为了降低 ...
- [ACM] poj 1088 滑雪 (内存搜索DFS)
滑雪 Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 73409 Accepted: 27141 Description ...
- android学习记录(三)百度地图错误---只有一个电话显示帧,没有地图内容。
安卓开发新手百度地图,刚开始碰到一个问题,没有地图信息,还有就是它只有一帧. 如图所示: 上网寻找说是key的问题,然后又一次申请.还是不行. 最后再次看了自己的Manifest文件,发现自己的< ...
- C#实现异步消息队列
原文:C#实现异步消息队列 拿到新书<.net框架设计>,到手之后迅速读了好多,虽然这本书不像很多教程一样从头到尾系统的讲明一些知识,但是从项目实战角度告诉我们如何使用我们的知识,从这本书 ...
- asp.net学习之ado.net(连接模式访问)
原文:asp.net学习之ado.net(连接模式访问) ado.net框架支持两种模式的数据访问: 连接模式(Connected)和非连接模式(disconnected).这一节介绍如何使用连 ...
- 对Unity3d C#手动处理异常产生
System.AppDomain.CurrentDomain.UnhandledException += new System.UnhandledExceptionEventHandler(_OnUn ...
- 十天学Linux内核之第六天---调度和内核同步
原文:十天学Linux内核之第六天---调度和内核同步 心情大好,昨晚我们实验室老大和我们聊了好久,作为已经在实验室待了快两年的大三工科男来说,老师让我们不要成为那种技术狗,代码工,说多了都是泪啊,, ...
- Android Widget 小部件(四---完结) 使用ListView、GridView、StackView、ViewFlipper展示Widget
官方有话这样说: A RemoteViews object (and, consequently, an App Widget) can support the following layout cl ...
- Android第一次打开应用程序,实现向导界面
转载请注明出处,谢谢http://blog.csdn.net/harryweasley/article/details/42079167 先说下思路:1.利用Preference存储数据,来记录是否是 ...
- [转载]Arguments
一.Arguments 该对象代表正在执行的函数和调用他的函数的参数. [function.]arguments[n] 参数function :选项.当前正在执行的 Function 对象的名字. n ...