C# 收益率关键字的奇迹

C# 收益率关键字的奇迹,c#,enumeration,yield,yield-return,C#,Enumeration,Yield,Yield Return,好的,当我在构建一个自定义枚举器时,我注意到了这个与产量有关的行为 假设你有这样的东西: public class EnumeratorExample { public static IEnumerable<int> GetSource(int startPoint) { int[] values = new int[]{1,2,3,4,5,6,7}; Contract.In

好的,当我在构建一个自定义枚举器时,我注意到了这个与产量有关的行为

假设你有这样的东西:

  public class EnumeratorExample 
  {

        public static IEnumerable<int> GetSource(int startPoint) 
        {
                int[] values = new int[]{1,2,3,4,5,6,7};
                Contract.Invariant(startPoint < values.Length);
                bool keepSearching = true;
                int index = startPoint;

                while(keepSearching) 
                {
                      yield return values[index];
                      //The mind reels here
                      index ++ 
                      keepSearching = index < values.Length;
                }
        }

  } 
公共类枚举器示例
{
公共静态IEnumerable GetSource(int startPoint)
{
int[]值=新的int[]{1,2,3,4,5,6,7};
收缩不变(起始点<值.长度);
bool keepsearch=true;
int索引=起始点;
同时(继续搜索)
{
收益率返回值[指数];
//我的脑子在这里转
索引++
keepSearching=索引<值.长度;
}
}
} 

从技术上讲,从函数返回后,是什么使编译器能够在后台执行index++和while循环中的其余代码?

编译器将代码重写到状态机中。您编写的单个方法被分成不同的部分。每次调用
MoveNext
(隐式或显式)时,状态都处于高级状态,并执行正确的代码块

如果您想了解更多详细信息,建议阅读:

  • C#中迭代器的实现及其后果-Raymond Chen
  • -乔恩·斯凯特
    • 产量是神奇的

      嗯,不是真的。编译器生成一个完整的类来生成您正在执行的枚举。它基本上是糖,让你的生活更简单

      阅读介绍


      编辑:这个错了。链接已更改,请再次检查是否有更改。

      编译器将代表您生成一个状态机

      根据语言规范:

      10.14迭代器

      10.14.4枚举器对象

      当函数成员返回 枚举器接口类型为 使用迭代器块实现, 调用函数成员不会 立即在 迭代器块。而是一个枚举器 对象被创建并返回。这 对象封装指定的代码 在迭代器块中,执行 迭代器块中的代码 在枚举器对象的 调用MoveNext方法。一 枚举器对象具有以下特性 特点:

      •它实现 IEnumerator和IEnumerator,其中 T是迭代器的屈服类型

      •它实现System.IDisposable

      •它是用一份 参数值(如果有)和实例 传递给函数成员的值

      •它有四种潜在状态, 之前、运行、暂停和之后, 并且最初处于before状态

      枚举器对象通常是 生成的编译器的实例 封装 迭代器块中的代码和 实现枚举器接口, 但还有其他的实施方法 这是可能的。如果枚举器类 是由编译器生成的 类将直接或间接嵌套 间接地,在包含 函数成员,它将具有 私人可访问性,它将 保留一个名称供编译器使用 (§2.4.2)

      为了了解这一点,以下是Reflector如何反编译您的类:

      public class EnumeratorExample
      {
          // Methods
          public static IEnumerable<int> GetSource(int startPoint)
          {
              return new <GetSource>d__0(-2) { <>3__startPoint = startPoint };
          }
      
          // Nested Types
          [CompilerGenerated]
          private sealed class <GetSource>d__0 : IEnumerable<int>, IEnumerable, IEnumerator<int>, IEnumerator, IDisposable
          {
              // Fields
              private int <>1__state;
              private int <>2__current;
              public int <>3__startPoint;
              private int <>l__initialThreadId;
              public int <index>5__3;
              public bool <keepSearching>5__2;
              public int[] <values>5__1;
              public int startPoint;
      
              // Methods
              [DebuggerHidden]
              public <GetSource>d__0(int <>1__state)
              {
                  this.<>1__state = <>1__state;
                  this.<>l__initialThreadId = Thread.CurrentThread.ManagedThreadId;
              }
      
              private bool MoveNext()
              {
                  switch (this.<>1__state)
                  {
                      case 0:
                          this.<>1__state = -1;
                          this.<values>5__1 = new int[] { 1, 2, 3, 4, 5, 6, 7 };
                          this.<keepSearching>5__2 = true;
                          this.<index>5__3 = this.startPoint;
                          while (this.<keepSearching>5__2)
                          {
                              this.<>2__current = this.<values>5__1[this.<index>5__3];
                              this.<>1__state = 1;
                              return true;
                          Label_0073:
                              this.<>1__state = -1;
                              this.<index>5__3++;
                              this.<keepSearching>5__2 = this.<index>5__3 < this.<values>5__1.Length;
                          }
                          break;
      
                      case 1:
                          goto Label_0073;
                  }
                  return false;
              }
      
              [DebuggerHidden]
              IEnumerator<int> IEnumerable<int>.GetEnumerator()
              {
                  EnumeratorExample.<GetSource>d__0 d__;
                  if ((Thread.CurrentThread.ManagedThreadId == this.<>l__initialThreadId) && (this.<>1__state == -2))
                  {
                      this.<>1__state = 0;
                      d__ = this;
                  }
                  else
                  {
                      d__ = new EnumeratorExample.<GetSource>d__0(0);
                  }
                  d__.startPoint = this.<>3__startPoint;
                  return d__;
              }
      
              [DebuggerHidden]
              IEnumerator IEnumerable.GetEnumerator()
              {
                  return this.System.Collections.Generic.IEnumerable<System.Int32>.GetEnumerator();
              }
      
              [DebuggerHidden]
              void IEnumerator.Reset()
              {
                  throw new NotSupportedException();
              }
      
              void IDisposable.Dispose()
              {
              }
      
              // Properties
              int IEnumerator<int>.Current
              {
                  [DebuggerHidden]
                  get
                  {
                      return this.<>2__current;
                  }
              }
      
              object IEnumerator.Current
              {
                  [DebuggerHidden]
                  get
                  {
                      return this.<>2__current;
                  }
              }
          }
      }
      
      公共类枚举器示例
      {
      //方法
      公共静态IEnumerable GetSource(int startPoint)
      {
      返回新的d_uu0(-2){3_uustartpoint=startPoint};
      }
      //嵌套类型
      [编译生成]
      私有密封类d_u0:IEnumerable,IEnumerable,IEnumerator,IEnumerator,IDisposable
      {
      //田地
      私立国际1____州;
      专用int 2_uuu电流;
      公共int 3___起点;
      private int l__initialThreadId;
      公共int 5___3;
      公共图书馆5_uu2;
      公共int[]5___1;
      公共国际起点;
      //方法
      [调试程序隐藏]
      公共数据0(内部1状态)
      {
      这个1.1__状态=1__状态;
      this.l__initialThreadId=Thread.CurrentThread.ManagedThreadId;
      }
      私有布尔移动下一个()
      {
      开关(此.1___状态)
      {
      案例0:
      该状态为-1;
      this.5_uu1=新的int[]{1,2,3,4,5,6,7};
      这1.5__2=真;
      this.5_uu3=this.startPoint;
      而(这是第2.5条)
      {
      这个.2___电流=这个.5__1[这个.5__3];
      该状态=1;
      返回true;
      标签_0073:
      该状态为-1;
      这个.5_uu3++;
      此.5_uuu2=此.5_uu3<此.5_uu1.长度;
      }
      打破
      案例1:
      goto标签_0073;
      }
      返回false;
      }
      [调试程序隐藏]
      IEnumerator IEnumerable.GetEnumerator()
      {
      枚举数示例.d_uu0 d_uuu;
      if((Thread.CurrentThread.ManagedThreadId==this.l_uinitialThreadId)&&(this.1_u状态==-2))
      {
      该状态=0;
      d_u;=这;
      }
      其他的
      {
      d_uu=新枚举数示例.d_u0(0);
      }
      d_uuu.startPoint=此.3_uuu起始点;
      返回d__;
      }
      [调试程序隐藏]
      IEnumerator IEnumerable.GetEnumerator()
      {
      返回此.System.Collections.Generic.IEnumerable.GetEnumerator();
      }
      [调试程序隐藏]
      void IEnumerator.Reset()
      {
      抛出新的NotSupportedException();
      }
      void IDisposable.Dispose()无效
      {
      }
      //性质
      国际酒店