收益率的工作模式

use*_*276 12 c# enumeration

当我有一个代码块

static void Main()
{

  foreach (int i in YieldDemo.SupplyIntegers())
  {
    Console.WriteLine("{0} is consumed by foreach iteration", i);
  }
}


 class YieldDemo
  {
    public static IEnumerable<int> SupplyIntegers()
     {
         yield return 1;
         yield return 2;
          yield return 3;
       }
   }
Run Code Online (Sandbox Code Playgroud)

我可以将收益率收益背后的原理解释为

  1. Main()调用SupplyIntegers()
  2. |1| |2| |3| are stored in contiguous memory block.Pointer of "IEnumerator" Moves to |1|
  3. 控制从SupplyInteger()返回到Main().
  4. Main()打印该值
  5. 指针移动到| 2 |,依此类推.

澄清:

(1)通常我们将在函数内部允许一个有效的return语句.当多个yield return,yield return,...语句出现时C#如何处理?

(2)一旦遇到回报,就无法再次控制回到SupplyIntegers(),如果允许则不会再从1开始收益?我的意思是收益率1?

Mar*_*ell 33

不 - 远非如此; 我会为你写一个长手版......它太蹩脚了!


请注意,如果您了解它foreach实际上是有帮助的:

using(var iterator = YieldDemo.SupplyIntegers().GetEnumerator()) {
    int i;
    while(iterator.MoveNext()) {
        i = iterator.Current;
         Console.WriteLine("{0} is consumed by foreach iteration", i);
    }
}
Run Code Online (Sandbox Code Playgroud)
using System;
using System.Collections;
using System.Collections.Generic;
static class Program
{
    static void Main()
    {

        foreach (int i in YieldDemo.SupplyIntegers())
        {
            Console.WriteLine("{0} is consumed by foreach iteration", i);
        }
    }
}

 class YieldDemo
  {

    public static IEnumerable<int> SupplyIntegers()
     {
         return new YieldEnumerable();
       }
    class YieldEnumerable : IEnumerable<int>
    {
        public IEnumerator<int> GetEnumerator()
        {
            return new YieldIterator();
        }
        IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
    }
    class YieldIterator : IEnumerator<int>
    {
        private int state = 0;
        private int value;
        public int Current { get { return value; } }
        object IEnumerator.Current { get { return Current; } }
        void IEnumerator.Reset() { throw new NotSupportedException(); }
        void IDisposable.Dispose() { }
        public bool MoveNext()
        {
            switch (state)
            {
                case 0: value = 1; state = 1;  return true;
                case 1: value = 2; state = 2;  return true;
                case 2: value = 3; state = 3; return true;
                default: return false;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,它在迭代器中构建了一个状态机,状态机逐步推进MoveNext.我已经将模式与state字段一起使用,因为您可以看到这对于更复杂的迭代器是如何工作的.

重要的:

  • 迭代器块中的任何变量都将成为状态机上的字段
  • 如果你有一个finally块(包括using),它会进入Dispose()
  • 导致yield return成为case(大致)的代码部分
  • yield break成为state = -1; return false;(或类似)

C#编译器执行此操作的方式非常复杂,但它使编写迭代器变得轻而易举.

  • 令人难以置信的是,人们在它实际上是一个有用的答案之前提出了这个建议. (2认同)