您的位置:首页 > 编程语言 > C#

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”问题,到底其作用是怎么发挥的?我是用单步调试将其大概的调用顺序摸清楚的。先给出源程序,诸君可将其复制建立工程然后对比。

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: