博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
从IL认识关键字(二)
阅读量:4573 次
发布时间:2019-06-08

本文共 2807 字,大约阅读时间需要 9 分钟。

关键字

     研究了foreach关键字,foreach关键字需要实现IEnumerable接口,实现GetEnumerator()方法。实现Enumerator()方法,很多时候用到yield关键字,今天我们研究一下yield关键字。

MSDN解释

  1.  yield 关键字向编译器指示它所在的方法是迭代器块。
  2. 编译器生成一个类来实现迭代器块中表示的行为。
  3. 在迭代器块中, yield 关键字与 return 关键字结合使用,向枚举器对象提供值。
  4. yield 关键字也可与 break 结合使用,表示迭代结束。

 其实MSDN已经解释清楚,今天我们主要研究第二点,C#会根据yield关键字生成一个类,看看这个类是怎样的。

C# IL Code

     先从简单例子看,只有一个值的迭代器

public static IEnumerable Test(){    yield return 10;}

对应的IL

.maxstack 2.locals init ([0] class Yield.Program/
d__0 d__,[1] class [mscorlib]System.Collections.IEnumerable enumerable)L_0000: ldc.i4.s -2L_0002: newobj instance void Yield.Program/
d__0::.ctor(int32)L_0007: stloc.0 L_0008: ldloc.0 L_0009: stloc.1 L_000a: br.s L_000cL_000c: ldloc.1 L_000d: ret

 <Test>d_0这个就是编译器生成的一个类,这段代码翻译成真正的运行代码如下

public static System.Collections.IEnumerable YieldOnly(){    return new d__0(-2);}
public 
d__0(int <>1__state){ this.<>1__state = <>1__state; this.<>l__initialThreadId = Thread.CurrentThread.ManagedThreadId;}

      这个就是<Test>d_0的构造函数。那究竟d_0这个类是怎样的,由于篇幅有限,这里不全贴出来。有兴趣同学自己可以反编译一下,看看就清楚。它生成时一个密封类,基础IEnumerable,IEnumerator两个接口,说白了就是一个迭代器。

[CompilerGenerated]private sealed class 
d__0 : IEnumerable
, IEnumerable, IEnumerator, IEnumerator, IDisposable{ ....}

下面主要贴出两个方法解释。

private bool MoveNext(){    switch (this.<>1__state)    {        case 0:            this.<>1__state = -1;            this.<>2__current = 10;            this.<>1__state = 1;            return true;        case 1:            this.<>1__state = -1;            break;    }    return false;}

  看到这里有人奇怪 _state = -2, 这里返回false,就不能遍历。上一篇我们说了foreach的原理,它是先调用GetEnumerator()获取迭代器对象,再遍历。

IEnumerator IEnumerable.GetEnumerator(){    if ((Thread.CurrentThread.ManagedThreadId == this.<>l__initialThreadId) && (this.<>1__state == -2))    {        this.<>1__state = 0;        return this;    }    return new Program.
d__0(0);}

     初始化放在这里,这里不知道为什么会判断一个是不是当前的线程,难道它还会跨线程调用。

   

循环的yield

public System.Collections.IEnumerable YieldCycle(){    for (int i = 0; i < 10; i++)    {        yield return i;    }}

对应MoveNext()

private bool MoveNext(){    switch (this.<>1__state)    {        case 0:            this.<>1__state = -1;            this.5__7 = 0;            while (this.5__7 < 10)            {
          //1.迭代 this.<>2__current = this.5__7;      this.<>1__state = 1; return true;        //2.叠加 Label_004B: this.<>1__state = -1; this.5__7++; } break; case 1: goto Label_004B; } return false;}

      循环语句基本分为两个模块,一个迭代的部分,一个是叠加的部分。对于有判断条件的yield return的,会将叠加部分拆分。

下一篇关键字

      以上只是本人的理解与实践,如有错误不足之处希望理解包容,下一篇讨论using关键字

转载于:https://www.cnblogs.com/WilsonPan/archive/2013/02/06/2900441.html

你可能感兴趣的文章
BZOJ 1572 贪心(priority_queue)
查看>>
【洛谷】【搜索(dfs)】P3956 棋盘
查看>>
python-面向对象进阶
查看>>
CentOS 7.4升级curl和git到最新版本
查看>>
[Leetcode][JAVA] Surrounded Regions
查看>>
【原创】无法在web服务器上启动调试
查看>>
Solr In Action 笔记(2) 之 评分机制(相似性计算)
查看>>
How do you build a database?
查看>>
XtraReport 一张纸打印3条记录
查看>>
Python爬虫之一
查看>>
[Tarjan][割点] 洛谷 P3469 BLO-Blockade
查看>>
WCF系列学习5天速成
查看>>
CentOS下JRE环境变量配置
查看>>
PHP的序列化和json以及区别
查看>>
【转】Spring 的下载、安装和使用
查看>>
53. 最大子序和
查看>>
vue组件创建的三种方式
查看>>
PAT_B_1015 德才论(有待改进)
查看>>
Jersey入门——对Json的支持
查看>>
Spring MVC入门
查看>>