c# yield关键字原理
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# yield关键字原理的更多相关文章
- c# yield关键字原理详解
c# yield关键字的用法 1.yield实现的功能 yield return: 先看下面的代码,通过yield return实现了类似用foreach遍历数组的功能,说明yield return也 ...
- python中的yield关键字
yield关键字一直困扰了我很久,一直也没有弄明白,现在将暂时理解的yield记录如下,供参考: 关键词:可迭代对象,生成器,迭代器 一.可迭代对象: 可迭代对象:可迭代对象是一个泛称,只要可以用fo ...
- C# 中yield关键字解析
前言 前段时间了解到yield关键字,一直觉得还不错.今天给大家分享一下yield关键字的用法.yield return 返回集合不是一次性返回所有集合元素,而是一次调用返回一个元素.具体如何使用yi ...
- c# 递归 yield关键字的用法
1.yield实现的功能 yield return: 先看下面的代码,通过yield return实现了类似用foreach遍历数组的功能,说明yield return也是用来实现迭代器的功能的. u ...
- 从yield关键字看IEnumerable和Collection的区别
C#的yield关键字由来以久,如果我没有记错的话,应该是在C# 2.0中被引入的.相信大家此关键字的用法已经了然于胸,很多人也了解yield背后的“延迟赋值”机制.但是即使你知道这个机制,你也很容易 ...
- .NET中的yield关键字
浅谈yield http://www.cnblogs.com/qlb5626267/archive/2009/05/08/1452517.html .NET中yield关键字的用法 http://bl ...
- 使用yield关键字让自定义集合实现foreach遍历
一般来说当我们创建自定义集合的时候为了让其能支持foreach遍历,就只能让其实现IEnumerable接口(可能还要实现IEnumerator接口) 但是我们也可以通过使用yield关键字构建的迭代 ...
- C#的yield关键字
using System; using System.Collections.Generic; using System.Reflection; using System.Text.RegularEx ...
- 从range和xrange的性能对比到yield关键字(中)
上节提出了range和xrange的效率问题,这节我们来探究其中的原因 yield的使用 我们看下面的程序: #coding: utf-8 def test(): print 4 print ...
随机推荐
- uniqid() 函数 和 microtime()函数
uniqid() 函数基于以微秒计的当前时间,生成一个唯一的 ID.语法 uniqid(prefix,more_entropy) 参数 描述prefix 可选.为 ID 规定前缀.如果 ...
- centos系统查看本机IP地址
centos系统查看本机IP地址,输入 ifconfig -a查看 centos查询上网公网IP输入 curl ifconfig.me 命令即可查看 centos查询上网网关IP,tracepath ...
- setjmp和longjmp
此文是学习 C专家编程 中的笔记. setjmp和longjmp是C语言所独有的,它们部分弥补了C语言有限的转移能力. 函数说明(来自wiki百科): int setjmp(jmp_buf env) ...
- HiveServer2的配置使用
HiveServer2的配置和使用 hive-site.xml配置 hiveserver2的配置 <property> <name>hive.support.concurren ...
- WOJ 43 电话邀请
并查集缩点这个trick感觉明明用得很广泛,为什么以前都不知道…… 先把$m$条线路从小到大排个序,这样可以保证之前合并出来的一定是最小的,大的代价不会把小的覆盖掉. 维护两个并查集,一个用来缩点,另 ...
- IDEA工作中常用快捷键
ctrl+shift+t: Ubuntu中在一个工具栏中打开两个终端 shift+shift: 搜索任何类 ctrl+N: 搜索任何类 ctrl+right: forward----自定义 ctrl+ ...
- MVC Areas
ASP.NET MVC中,是依靠某些文件夹以及类的固定命名规则去组织model实体层,views视图层和控制层的.如果是大规模的应用程序,经常会由不同功能的模块组成,而每个功能模块都由MVC中的三层所 ...
- Cookies的两种存取方式
我们在使用webview开发时,少不了和cookie打交道,在网页端我这使用的是asp.net开发的,安卓下的cookie和windows平台下还是有些不同的,后来看了看,原来有两种cookie的存取 ...
- ASP.NET MVC底层原理与框架
前言 鄙人有一毛病,喜欢钻研原理性的东西,感觉只知道怎么用还不太够,更想知道如何实现的以及为什么会这样. 暑假的时候做积分系统是第一次接触MVC,感觉MVC就是一个框架,分为Module ,view和 ...
- 洛谷P3901 数列找不同(莫队)
传送门 我不管我不管我就是要用莫队 直接用莫队裸上 //minamoto #include<iostream> #include<cstdio> #include<alg ...