C# 关于"yield return"的研究(转载)
2012-11-26 15:17
357 查看
转载自:http://hi.baidu.com/algorithmanlxl/item/d94211d17a831c2039f6f792
这里的研究是借助了http://jangmon.blogbus.com/logs/36380490.html的帮助,虽然其中有些代码出现了错误,而且颇多细节没说清楚,但是对鄙人的启发意义很大。各位可以去该链接学习一下。而事实上,由于C#在.net框架中的高级特性和技术内幕很难深层次的说清楚,有些东西鄙人也是不甚明了。具体的接口说明和解释可以看看上面那篇博文,在这里我是想说说困扰很多人的"yield return”问题,到底其作用是怎么发挥的?我是用单步调试将其大概的调用顺序摸清楚的。先给出源程序,诸君可将其复制建立工程然后对比。
上面注释的部分引用了"yield return”,其功能相当于下面所有代码!为什么呢,其实要从底层来说也很难解释得清楚,大家可以在foreach之前设一个断点,然后调试运行,会发现断点运行到foreach那一行的时候,会先编译"helloCollection",然后跳到下面的public IEnumerator GetEnumerator()执行该函数,而函数中原本的yield return会为HelloCollection类自动生成代码,就是多了Enumerator这个内部类的实现,且public IEnumerator GetEnumerator()里面的代码也会变成
Enumerator enumerator = new Enumerator(0);
return enumerator;
那么在运行到Enumerator enumerator = new Enumerator(0);的时候就会发现又跳到了Enumerator内部类的构造函数,构造完成后,回去编译foreach那行的"in",会发现又跳到了MoveNext函数,执行完毕后再去编译foreach那行的"string s”,发现跳到了Current字段的定义,调用了get方法,其内部估计是对s执行了赋值,不确定(暂且这样理解)。以此类推,最后会发现直到执行MoveNext返回了false,那么就会跳到了Dispose(),最后就这样了。
上面讲述的是通过断点来分析其运行的,而事实上如果比较简洁地去说的话,foreach这一行会被编译成IEnumerator e=helloCollection.GetEnumerator(),并自动生成一个while(e.MoveNext())循环实现了整个聚合的遍历。
本文转载自:http://hi.baidu.com/algorithmanlxl/item/d94211d17a831c2039f6f792
这里的研究是借助了http://jangmon.blogbus.com/logs/36380490.html的帮助,虽然其中有些代码出现了错误,而且颇多细节没说清楚,但是对鄙人的启发意义很大。各位可以去该链接学习一下。而事实上,由于C#在.net框架中的高级特性和技术内幕很难深层次的说清楚,有些东西鄙人也是不甚明了。具体的接口说明和解释可以看看上面那篇博文,在这里我是想说说困扰很多人的"yield return”问题,到底其作用是怎么发挥的?我是用单步调试将其大概的调用顺序摸清楚的。先给出源程序,诸君可将其复制建立工程然后对比。
class Program { static void Main(string[] args) { HelloCollection helloCollection = new HelloCollection(); foreach (string s in helloCollection) Console.WriteLine(s); Console.ReadKey(); } //public class HelloCollection : IEnumerable //{ // public IEnumerator GetEnumerator() // { // yield return "Hello"; // yield return "World"; // } //} public class HelloCollection : IEnumerable { public IEnumerator GetEnumerator() { Enumerator enumerator = new Enumerator(0); return enumerator; } public class Enumerator : IEnumerator, IDisposable { private int state; private object current; public Enumerator(int state) { this.state = state; } public bool MoveNext() { switch (state) { case 0: current = "Hello"; state = 1; return true; case 1: current = "World"; state = 2; return true; case 2: break; } return false; } public void Reset() { throw new NotSupportedException(); } public object Current { get { return current; } } public void Dispose() { } } } }
上面注释的部分引用了"yield return”,其功能相当于下面所有代码!为什么呢,其实要从底层来说也很难解释得清楚,大家可以在foreach之前设一个断点,然后调试运行,会发现断点运行到foreach那一行的时候,会先编译"helloCollection",然后跳到下面的public IEnumerator GetEnumerator()执行该函数,而函数中原本的yield return会为HelloCollection类自动生成代码,就是多了Enumerator这个内部类的实现,且public IEnumerator GetEnumerator()里面的代码也会变成
Enumerator enumerator = new Enumerator(0);
return enumerator;
那么在运行到Enumerator enumerator = new Enumerator(0);的时候就会发现又跳到了Enumerator内部类的构造函数,构造完成后,回去编译foreach那行的"in",会发现又跳到了MoveNext函数,执行完毕后再去编译foreach那行的"string s”,发现跳到了Current字段的定义,调用了get方法,其内部估计是对s执行了赋值,不确定(暂且这样理解)。以此类推,最后会发现直到执行MoveNext返回了false,那么就会跳到了Dispose(),最后就这样了。
上面讲述的是通过断点来分析其运行的,而事实上如果比较简洁地去说的话,foreach这一行会被编译成IEnumerator e=helloCollection.GetEnumerator(),并自动生成一个while(e.MoveNext())循环实现了整个聚合的遍历。
本文转载自:http://hi.baidu.com/algorithmanlxl/item/d94211d17a831c2039f6f792
相关文章推荐
- 关于C#之yield return 话题
- <C#>关于string.Empty & "" & null 的讨论
- C#关于AutoResetEvent的使用介绍[转载]
- 关于extern "c"的用法解析(转载)
- C#关于AutoResetEvent的使用介绍[转载]
- 关于Ajax无刷新分页技术的一些研究 c#
- 【转载】关于C#格式化字符串,最好的总结
- 关于SPEEX和语音的研究(转载的基础上加原创)
- C#程序实现动态调用DLL的研究(转载)
- C#程序实现动态调用DLL的研究(转载)
- C#关于数组Console.Write("{0,4:d}",c[i,j]);是什么意思
- 关于在VS2008和VS2010中禁用及卸载Visual Assist X的方法研究——转载
- CLR via C# 读书笔记(三)关于"is" 和"as"操作符
- CLR via C# 读书笔记(六)关于"字符串留用"
- <C#>关于string.Empty & "" & null 的讨论
- C#在OpenGL编程中的应用--关于摩尔纹的研究
- C#关于AutoResetEvent的使用介绍[转载]
- 关于《用C#编写ActiveX控件》的几点说明 转载
- C#关于AutoResetEvent的使用介绍[转载]
- C# Excel 行高,列宽,合并单元格,单元格边框线,冻结(转载) - 关于C#操作EXCLE常见操作比较全的