https://www.cnblogs.com/blueberryzzz/p/8678700.html

c# yield关键字原理详解

1.yield实现的功能
yield return:
先看下面的代码,通过yield return实现了类似用foreach遍历数组的功能,说明yield return也是用来实现迭代器的功能的。

using static System.Console;
using System.Collections.Generic; class Program
{
//一个返回类型为IEnumerable<int>,其中包含三个yield return
public static IEnumerable<int> enumerableFuc()
{
yield return 1;
yield return 2;
yield return 3;
} static void Main(string[] args)
{
//通过foreach循环迭代此函数
foreach(int item in enumerableFuc())
{
WriteLine(item);
}
ReadKey();
}
} 输出结果:
1
2
3

yield break:
再看下面的代码,只输出了1,2,没有输出3,说明这个迭代器被yield break停掉了,所以yield break是用来终止迭代的。

using static System.Console;
using System.Collections.Generic;
class Program
{
//一个返回类型为IEnumerable<int>,其中包含三个yield return
public static IEnumerable<int> enumerableFuc()
{
yield return 1;
yield return 2;
yield break;
yield return 3;
} static void Main(string[] args)
{
//通过foreach循环迭代此函数
foreach(int item in enumerableFuc())
{
WriteLine(item);
}
ReadKey();
}
} 输出结果:
1
2

2.只能使用在返回类型必须为 IEnumerable、IEnumerable<T>、IEnumerator 或 IEnumerator<T>的方法、运算符、get访问器中。

3.yield关键字的实现原理
我们用while循环代替foreach循环,发现我们虽然没有实现GetEnumerator(),也没有实现对应的IEnumerator的MoveNext(),和Current属性,但是我们仍然能正常使用这些函数。

class Program
{
//一个返回类型为IEnumerable<int>,其中包含三个yield return
public static IEnumerable<int> enumerableFuc()
{
yield return 1;
yield return 2;
yield return 3;
} static void Main(string[] args)
{
//用while循环代替foreach
IEnumerator<int> enumerator = enumerableFuc().GetEnumerator();
while (enumerator.MoveNext())
{
int current = enumerator.Current;
WriteLine(current);
}
ReadKey();
}
} 输出结果:
1
2
3

至于为什么会出现这种情况,我们可以用ILSpy对生成的exe进行反编译来找到原因。
由于直接反编译成C#会变为原样

所以我们选择反编译为带C#注释的IL代码,虽然可读性差点,但是可以详细的了解其中过的原理。
先来看Program翻译的情况,编译的时候自动生成了一个新的类。

接下来我们来仔细看这些代码,EnumerableFuc()返回了这个新的类。

看这个代码自动生成的类的实现,发现它继承了IEnumerable、IEnumerable<T>、IEnumerator 或 IEnumerator<T>,这时我们应该已经能猜到这个新的类就是我们没有实现对应的IEnumerator的MoveNext(),和Current属性,但是我们仍然能正常使用这些函数的原因了。

我们再来看一下这个类具体是如何实现迭代的呢,我们主要来看一下MoveNext()函数


每次调用MoveNext()函数都会将state加1,一共进行了4次迭代,前三次返回true,最后一次返回false,代表迭代结束。这四次迭代对应被3个yield return语句分成4部分的enumberableFuc()中的语句。

用enumberableFuc()来进行迭代的真实流程就是:
1.运行enumberableFuc()函数,获取代码自动生成的类的实例。
2.接着调用GetEnumberator()函数,将获取的类自己作为迭代器开始迭代。
3.每次运行MoveNext(),state增加1,通过switch语句可以让每次调用MoveNext()的时候执行不同部分的代码。
4。MoveNext()返回false,结束。
这也能说明yield关键字其实是一种语法糖,最终还是通过实现IEnumberable<T>、IEnumberable、IEnumberator<T>和IEnumberator接口实现的迭代功能。

 
 
标签: c#.NET
 
 

c# yield关键字原理的更多相关文章

  1. c# yield关键字原理详解

    c# yield关键字的用法 1.yield实现的功能 yield return: 先看下面的代码,通过yield return实现了类似用foreach遍历数组的功能,说明yield return也 ...

  2. python中的yield关键字

    yield关键字一直困扰了我很久,一直也没有弄明白,现在将暂时理解的yield记录如下,供参考: 关键词:可迭代对象,生成器,迭代器 一.可迭代对象: 可迭代对象:可迭代对象是一个泛称,只要可以用fo ...

  3. C# 中yield关键字解析

    前言 前段时间了解到yield关键字,一直觉得还不错.今天给大家分享一下yield关键字的用法.yield return 返回集合不是一次性返回所有集合元素,而是一次调用返回一个元素.具体如何使用yi ...

  4. c# 递归 yield关键字的用法

    1.yield实现的功能 yield return: 先看下面的代码,通过yield return实现了类似用foreach遍历数组的功能,说明yield return也是用来实现迭代器的功能的. u ...

  5. 从yield关键字看IEnumerable和Collection的区别

    C#的yield关键字由来以久,如果我没有记错的话,应该是在C# 2.0中被引入的.相信大家此关键字的用法已经了然于胸,很多人也了解yield背后的“延迟赋值”机制.但是即使你知道这个机制,你也很容易 ...

  6. .NET中的yield关键字

    浅谈yield http://www.cnblogs.com/qlb5626267/archive/2009/05/08/1452517.html .NET中yield关键字的用法 http://bl ...

  7. 使用yield关键字让自定义集合实现foreach遍历

    一般来说当我们创建自定义集合的时候为了让其能支持foreach遍历,就只能让其实现IEnumerable接口(可能还要实现IEnumerator接口) 但是我们也可以通过使用yield关键字构建的迭代 ...

  8. C#的yield关键字

    using System; using System.Collections.Generic; using System.Reflection; using System.Text.RegularEx ...

  9. 从range和xrange的性能对比到yield关键字(中)

    上节提出了range和xrange的效率问题,这节我们来探究其中的原因   yield的使用   我们看下面的程序: #coding: utf-8 def test(): print 4 print ...

随机推荐

  1. auth 权限控制

    一. 权限介绍所谓权限控制,大部分是在管理后台上使用.比如超级管理员登录,会得到所有操作的控制权:认证专员,只能给会员做认证操作:审核专员,只能操作内容的审核.删除.加精等操作,以此类推.那么 Thi ...

  2. 36-图像有用区(dfs, bfs)

    http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=92 图像有用区域 时间限制:3000 ms  |  内存限制:65535 KB 难度:4   ...

  3. 树莓派研究笔记(5)-- FM网络收音机

    1. 安装mpc sudo apt-get install mpd mpc 2.添加流.注意,这里有个坑,如果下面这个地址不能用,那么就无法测试了.建议先下载一个龙卷风或者酷狗网络收音机,然后添加地址 ...

  4. Visual Studio 2012自动添加注释(如版权信息等)

    http://blog.csdn.net/jiejiaozhufu/article/details/16357721注释宏的原码 /********************************** ...

  5. [译]Javascript基础

    本文翻译youtube上的up主kudvenkat的javascript tutorial播放单 源地址在此: https://www.youtube.com/watch?v=PMsVM7rjupU& ...

  6. 原型模式与serializable

    写原型模式时课件上有一个实现模式是利用可串行化接口实现,然后就发现那个代码(如下),串行化接口里面没有函数,这种接口被曾为标记接口,implements这个接口后就可以对其进行各种流操作了,其实就是O ...

  7. c# 省市区联动

    http://www.matrixkey.com.cn/blog/article.asp?id=427 建议楼主去这里看看:http://pagetalks.com/2010/03/22/jquery ...

  8. js 值传递,引用传递

    参考:http://www.cnblogs.com/lcngu/p/5876273.html JS的基本类型,是按值传递的. 对象类型按共享传递的(call by sharing,也叫按对象传递.按对 ...

  9. 动态合并GridView数据行DataRow的列

    前段时间,Insus.NET一直在演示GridView控件Header头行或列:<动态变更GridView控件列名>和<动态合并或定制GridView控件Header头某些列> ...

  10. meta标签使用

    META标签分两大部分:HTTP标题信息(HTTP-EQUIV)和页面描述信息(NAME). ★HTTP-EQUIV HTTP-EQUIV类似于HTTP的头部协议,它回应给浏览器一些有用的信息,以帮助 ...