首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >收益率工作模式

收益率工作模式
EN

Stack Overflow用户
提问于 2009-10-20 19:42:09
回答 3查看 6.2K关注 0票数 12

当我有一个代码块

代码语言:javascript
复制
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;
       }
   }

我能否解释收益回报背后的原则是

  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)通常我们将有一个有效的返回语句允许在function.How中执行C#处理,当多个收益率返回时,收益率返回,.有陈述吗?

(2)一旦遇到返回,就无法再次控制返回到SupplyIntegers(),如果允许的话,产量不会再次从1开始吗?我是说回报1?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2009-10-20 19:44:57

不,不是的,我会给你写个长版的.太下流了!

注意,如果您理解foreach实际上是:

代码语言:javascript
复制
using(var iterator = YieldDemo.SupplyIntegers().GetEnumerator()) {
    int i;
    while(iterator.MoveNext()) {
        i = iterator.Current;
         Console.WriteLine("{0} is consumed by foreach iteration", i);
    }
}
代码语言:javascript
复制
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;
            }
        }
    }
}

如您所见,它在迭代器中构建状态机,状态机由MoveNext推进。我在state字段中使用了这种模式,因为您可以看到这对于更复杂的迭代器是如何工作的。

重要的是:

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

C#编译器这样做是非常复杂的,但它使编写迭代器变得轻而易举。

票数 34
EN

Stack Overflow用户

发布于 2009-10-20 19:47:34

它只是语法糖,.net为您生成IEnumerator类并实现MoveNext、当前方法和重置方法,而不是生成IEnumarable类GetEnumerator,后者返回IEnumerator,您可以通过.net反射器或ildasm看到神奇的类。

还请参见这里

票数 3
EN

Stack Overflow用户

发布于 2009-10-20 19:56:27

简单地说,迭代器块(如果可能的话是带有yield语句的方法)由编译器转换为编译器生成的类。该类实现IEnumerator,并将yield语句转换为该类的“状态”。

例如,这是:

代码语言:javascript
复制
yield return 1;
yield return 2;
yield return 3;

可能会被转换成类似于:

代码语言:javascript
复制
switch (state)
{
    case 0: goto LABEL_A;
    case 1: goto LABEL_B;
    case 2: goto LABEL_C;
}
LABEL_A:
    return 1;
LABEL_B:
    return 2;
LABEL_C:
    return 3;

Iterator块可以看作是抽象的状态机。此代码将由IEnumerator的方法调用。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1596863

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档