foreach 在编译成IL后,实际代码如下:

即:foreach实际上是先调用可枚举对象的GetEnumerator方法,得到一个Enumerator对象,然后对Enumerator进行while循环的相关操作,然后得到可枚举对象中的每一个值。

可以把可枚举对象中的所有值想像成一个链表,Enumerator是链表的指针,Enumerator.Current是当前指向的元素,Enumerator.MoveNext是指针后移。于是用while循环便可以用类似遍历链表的方式得到对象中的所有值。

一个可枚举对象,本身必需实现IEnumerable接口(其中只有一个GetEnumerator方法)。

在GetEnumerator方法中,可以直接返回一个Enumerator对象用于枚举。

也可以用多个yield return返回所有需要枚举的值,yield 语句在这里会创建一个实现了IEnumerator接口的对象。

要注意的是,如果在方法中用了yield return,就不能用普通的return,且如果用了yield return,那么方法体中的代码不会在调用时运行,只会在枚举开始后(调用Enumerator.MoveNext())才开始运行。且每一次枚举都只会运行到下一个yield return。

class test : IEnumerable
{
public static int j = ;
public static string ss = "begin"; public int i = ;
public IEnumerable<string> a()
{
test.ss += "1111111111@"; //string[] aaaa = { "1", "2", "3" }; //return aaaa.AsEnumerable(); test.j++;
yield return test.j.ToString();
test.ss += "1111111111@";
test.j++;
yield return test.j.ToString();
test.j++;
yield return test.j.ToString(); } public IEnumerator GetEnumerator()
{
test.ss += "222222222222222@"; string[] aaaa = { "", "", "" }; return aaaa.GetEnumerator(); //test.j++;
//yield return test.j.ToString();
//test.j++;
//yield return test.j.ToString();
//test.j++;
//yield return test.j.ToString();
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(test.ss);
test t = new test(); Console.WriteLine(test.ss); var tb = t.GetEnumerator(); Console.WriteLine(test.ss);
var a = t.a(); Console.WriteLine(test.ss);
var b = a.GetEnumerator();
//var c = b.Current;
//b.MoveNext();
//Console.WriteLine(c);
//b.MoveNext();
Console.WriteLine(test.ss);
int i = ;
foreach (var s in t)
{
i++;
//test.j = i;
Console.WriteLine(test.j + " " + s);
} Console.WriteLine(test.ss); ReadLine();
}
}

如上面的代码,方法GetEnumerator中用的是普通的return,此时运行到

var tb = t.GetEnumerator();

输出是:begin222222222222222@

因为调用了t.GetEnumerator();自然会运行  test.ss += "222222222222222@"; 所以输出是  begin222222222222222@

但继续往下运行,无论是调用了test.a()还是test.a().GetEnumerator()   test.ss的值都没有再改变,也就是没有执行  test.ss += "1111111111@";  也就是此时方法test.a中的代码一直没得得到执行。

直到foreach开始后,即枚举开始(调用了MoveNext),才开始执行test.a方法体中的代码。

也就是说,包含yield return的方法,已经不是一个普通的方法,用普通的调用方式调用该方法,是不会执行里面的任何代码的,直到调用了Enumerator.MoveNext方法。
且每一次调用Enumerator.MoveNext方法,代码只会执行到下一个
yield return,并将该yield return返回的结果做为此次枚举的值。
												

最新文章

  1. [UWP]使用AdaptiveTrigger实现自适应布局
  2. 正定矩阵(positive definite matrix)
  3. Java程序设计之扑克牌
  4. PHP与apache环境配置
  5. python sorted和sort
  6. MyCat 学习笔记 第十一篇.数据分片 之 分片数据查询 ( select * from table_name limit 100000,100 )
  7. uva 11275 3D Triangles
  8. CJOJ 1943 【重庆八中模拟赛】寻找代表元(二分图最大匹配)
  9. win10汇编如何debug(小白向)
  10. SharePoint 列表项通过自定义WebService读取
  11. mysql for linux6.8单机版安装
  12. Java语法基础学习DayNineteen(反射机制)
  13. hadoop 遇到java.net.ConnectException: to 0.0.0.0:10020 failed on connection
  14. AngularJS 指令中的require
  15. CentOS配置bond
  16. 简单DP+暴力 POJ 1050
  17. IIS 与 Apache共存
  18. PHP的生命周期
  19. c#实现QQ群成员列表导出及邮件群发之邮件群发
  20. javascript array类型用法

热门文章

  1. HTTP 错误 404.3 - Forbidden
  2. 将批量下载的博客导入到手机后,通过豆约翰博客阅读器APP(Android手机)进行浏览,白字黑底,保护眼睛,图文并茂。
  3. Unity给力插件之LittleLocalization
  4. Bzoj 3747: [POI2015]Kinoman 线段树
  5. HW4.13
  6. python爬虫学习(3)_模拟登陆
  7. openstack kvm 虚拟机磁盘差异衍生
  8. 容联云通讯_提供网络通话、视频通话、视频会议、云呼叫中心、IM等融合通讯能力开放平台。
  9. 【python自动化第四篇:python入门进阶】
  10. Sublime ctags 函数跳转插件安装