Behind the scenes of the C# yield keyword(转)
https://startbigthinksmall.wordpress.com/2008/06/09/behind-the-scenes-of-the-c-yield-keyword/
Behind the scenes of the C# yield keyword
June 9, 2008 by Lars Corneliussen
After reading the great article about the code-saving yield keyword “Give way to the yield keyword” by Shay Friedman I thought it could be interesting to know how the yield keyword works behind the scenes.
…it doesn’t really end the method’s execution. yield return pauses the method execution and the next time you call it (for the next enumeration value), the method will continue to execute from the last yield return call. It sounds a bit confusing I think… (ShayF)
By using yield return within a method that returns IEnumerable or IEnumeratorthe language feature is activated.
Note: IEnumerable is kind of a stateless factory for Enumerators.IEnumerable.GetEnumerator() is thread safe and can be called multiple times, while the returned stateful Enumerator is just a helper for enumerating contained values once. By contract IEnumerator offers a Reset() method, but many implementations just throw a NotSupportedException.
Lets create an enumerator method that yields some Fibonacci nubmers.
public class YieldingClass
{
public IEnumerable<int> GetFibonachiSequence()
{
yield return ;
yield return ;
yield return ;
yield return ;
}
}
Note: Yield is not a feature of the .Net runtime. It is just a C# language feature which gets compiled into simple IL code by the C# compiler.
The compiler now generates a inner class with following signature (Reflector + some renaming):
[CompilerGenerated]
private sealed class YieldingEnumerator :
IEnumerable<object>, IEnumerator<object>
{
// Fields
private int state;
private int current;
public YieldingClass owner;
private int initialThreadId; // Methods
[DebuggerHidden]
public YieldingEnumerator(int state);
private bool MoveNext();
[DebuggerHidden]
IEnumerator<int> IEnumerable<int>.GetEnumerator();
[DebuggerHidden]
IEnumerator IEnumerable.GetEnumerator();
[DebuggerHidden]
void IEnumerator.Reset();
void IDisposable.Dispose(); // Properties
object IEnumerator<object>.Current
{ [DebuggerHidden] get; } object IEnumerator.Current
{ [DebuggerHidden] get; }
}
Each enumerator holds a state indicating:
- -2: Initialized as Enumerable. (Not yet an Enumerator)
- -1: Closed
- 0: Initialized as Enumerator.
If a new Enumerator is requested on the same instance, GetEnumerator() returns another new instance of YieldingEnumerator. - 1-n: Index of the yield return in the original GetFibonachiSequence()method. In case of nested enumerators or other more complex scenarios one yield return consumes more than one index.
The content of GetFibonachiSequence() is translated into YieldingEnumerator.MoveNext().
In our very simple scenario the code looks like this:
bool MoveNext()
{
switch (state)
{
case :
state = -;
current = ;
state = ;
return true; case :
state = -;
current = ;
state = ;
return true; case :
state = -;
current = ;
state = ;
return true; case :
state = -;
current = ;
state = ;
return true; case :
state = -;
break;
}
return false;
}
So far we easily could have created the classes and methods used to enable the yield keyword ourselves, too.
But in more complex scenarios Microsoft does some tricks, which won’t compile as C# – at least not how Reflector translates the resulting IL code.
Lets have a look at some code with a nested enumeration…
foreach(int i in new int[] {, , , , })
{
yield return i;
}
private bool MoveNext()
{
try
{
switch (state)
{
case 0:
state = -1;
state = 1;
this.values = new int[] { 1, 2, 3, 5, 8 };
this.currentPositionInValues = 0;
while (this.currentPositionInValues < this.values.Length)
{
current_i = this.values[this.currentPositionInValues];
current = current_i;
state = 2;
return true;
Label_007F:
state = 1;
this.currentPositionInValues++;
}
this.Finally2();
break; case 2:
goto Label_007F;
}
return false;
}
fault
{
this.System.IDisposable.Dispose();
}
}
[/sourcecode]
Now the states 1 and 2 are used to indicate whether the enumerator actually is at some point (2), or wether it is trying to retrieve the next value (1).
Two things would not compile:
- goto Label_007F is used to jump back into the iteration over int[] values. The C# goto statement is not able to jump into another statements context. But in IL this is totally valid as a while statement in MSIL is nothing but some gotos either.
- The fault is proper MSIL, but not supported in C#. Basically it acts as a finally which just is executed in case of an error.
Attention: As in anonymous delegates, parameters as well as local and instance variables are passed to the YieldingEnumerator only once. Read this great post on this: Variable Scoping in Anonymous Delegates in C#
Thanks for your attention!
Behind the scenes of the C# yield keyword(转)的更多相关文章
- What is the use of c# “Yield” keyword ?
What is the use of c# “Yield” keyword ? “Yield keyword helps us to do custom stateful iteration over ...
- What is the yield keyword used for in C#?
What is the yield keyword used for in C#? https://stackoverflow.com/a/39496/3782855 The yield keywor ...
- 【转向Javascript系列】深入理解Generators
随着Javascript语言的发展,ES6规范为我们带来了许多新的内容,其中生成器Generators是一项重要的特性.利用这一特性,我们可以简化迭代器的创建,更加令人兴奋的,是Generators允 ...
- .NET中的yield关键字
浅谈yield http://www.cnblogs.com/qlb5626267/archive/2009/05/08/1452517.html .NET中yield关键字的用法 http://bl ...
- Python关键字yield详解以及Iterable 和Iterator区别
迭代器(Iterator) 为了理解yield是什么,首先要明白生成器(generator)是什么,在讲生成器之前先说说迭代器(iterator),当创建一个列表(list)时,你可以逐个的读取每一项 ...
- [Python学习笔记-005] 理解yield
网络上介绍yield的文章很多,但大多讲得过于复杂或者追求全面以至于反而不好理解.本文用一个极简的例子给出参考资料[1]中的讲解,因为个人觉得其讲解最为通俗易懂,读者只需要对Python的列表有所了解 ...
- Python yield解析
Pyhton generators and the yield keyword At a glance,the yield statement is used to define generators ...
- yield return,yield break
转自, http://www.cnblogs.com/kingcat/archive/2012/07/11/2585943.html yield return 表示在迭代中下一个迭代时返回的数据,除此 ...
- Understanding Asynchronous IO With Python 3.4's Asyncio And Node.js
[转自]http://sahandsaba.com/understanding-asyncio-node-js-python-3-4.html Introduction I spent this su ...
随机推荐
- 实践作业4---DAY2阶段一。
由于CSDN博客没有班级博客栏目,所以在该项功能上无法与博客园进行对比,我们将就CSDN和博客园的博文发布功能进行对比.我们就CSDN和博客园的博文发布页面.后台管理界面.发布新博客及界面进行了全面的 ...
- Linux Basic学习笔记01
介绍课程: 中级: 初级:系统基础 中级:系统管理.服务安全及服务管理.Shell脚本: 高级: MySQL数据库: cache & storage 集群: Cluster lb: 4laye ...
- eclipse netbeans 代码模板
eclipse 代码模板 插入slf4j ${:import(org.slf4j.Logger,org.slf4j.LoggerFactory)} private static final Log ...
- SQL高性能分页
分页的场景就不多说了,无处不在. 方法一:利用row_number() with C as ( select ROW_NUMBER() over(order by orderdate,orderid) ...
- 访问SAP的RFC
.NET 环境Xp(sp3) vs2010, win2003 EN 32bit(sp2)winform,webform 引用sapnco.dll,sapnco_utils.dll(自动引用)配置文件需 ...
- Yii2 集成 adminlteasset
https://github.com/dmstr/yii2-adminlte-asset AdminLTE Asset Bundle Backend UI for Yii2 Framework, ba ...
- javascript总结20: 前端必读,浏览器内部工作原理(转)
目录 一.介绍 二.渲染引擎 三.解析与DOM树构建 四.渲染树构建 五.布局 六.绘制 七.动态变化 八.渲染引擎的线程 九.CSS2可视模型 英文原文:How Browsers Work: Beh ...
- Grails项目开发——前端请求跨域问题
Grails项目开发--前端请求跨域问题 最近做项目采用前后端分离的思想,使用Grails作为后台开发Restful API供前端调用. 在项目开发的过程中,遇到前端没办法通过ajax访问到后台接口的 ...
- 15、Semantic-UI之导航
15.1 面包屑导航 在Semantic-UI中有多种样式实现面包屑导航,类似 / > 等. 示例:定义定义基础面包屑导航 <div class="ui container& ...
- SlidesJS基本使用方法和官方文档解释
Slides – 是一个简单的,容易定制和风格化,的jQuery幻灯片插件. Slides提供褪色或幻灯片过渡效果,图像淡入淡出,图像预压,自动生成分页,循环,自动播放的自定义等很多选项. 用Slid ...