算法实现C#产量声明(Algorithm for implementing C# yield sta

2019-08-02 04:56发布

我很想搞清楚自己,但我想大致有什么算法与产量语句的功能转换成状态机来枚举? 例如如何C#关闭此:

IEnumerator<string> strings(IEnumerable<string> args)
 { IEnumerator<string> enumerator2 = getAnotherEnumerator();     
   foreach(var arg in arg) 
    { enumerator2.MoveNext();
      yield return arg+enumerator.Current;
    } 
 }

这个:

bool MoveNext()
 { switch (this.state)
    {
        case 0:
            this.state = -1;
            this.enumerator2 = getAnotherEnumerator();
            this.argsEnumerator = this.args.GetEnumerator();
            this.state = 1;
            while (this.argsEnumerator.MoveNext())
            {
                this.arg = this.argsEnumerator.Current;
                this.enumerator2.MoveNext();
                this.current = this.arg + this.enumerator2.Current;
                this.state = 2;
                return true;

              state1:
                this.state = 1;
            }
            this.state = -1;
            if (this.argsEnumerator != null) this.argsEnumerator.Dispose();
            break;

        case 2:
            goto state1;
    }
    return false;
}

当然,结果可以根据原来的代码是完全不同的。

Answer 1:

你正在寻找的特定代码示例涉及一系列变革。 请注意,这是该算法的大致描述。 所使用的编译器和它产生可以是不同的确切的代码的实际名称。 我们的想法是一样的,但是。

第一变换是“的foreach”变换,其将这样的代码:

foreach (var x in y)
{
   //body
}

这个代码:

var enumerator = y.GetEnumerator();
while (enumerator.MoveNext())
{
    var x = enumerator.Current;
    //body
}

if (y != null)
{
    enumerator.Dispose();
}

第二变换查找所有收率return语句在函数体,分配一个编号以每(状态值),并创建屈服后右一“转到标签”。

第三变换抬起所有的方法中的身体局部变量和函数参数成称为封闭的对象。

鉴于您的示例代码,这将类似于此:

 class ClosureEnumerable : IEnumerable<string>
 {
    private IEnumerable<string> args;
    private ClassType originalThis;
    public ClosureEnumerator(ClassType origThis, IEnumerable<string> args)
    {
        this.args = args;
        this.origianlThis = origThis;
    }
    public IEnumerator<string> GetEnumerator()
    {
        return new Closure(origThis, args);
    }
 }

class Closure : IEnumerator<string>
{
    public Closure(ClassType originalThis, IEnumerable<string> args)
    {
        state = 0;
        this.args = args;
        this.originalThis = originalThis;
    }

    private IEnumerable<string> args;
    private IEnumerator<string> enumerator2;
    private IEnumerator<string> argEnumerator;

    //- Here ClassType is the type of the object that contained the method
    //  This may be optimized away if the method does not access any 
    //  class members
    private ClassType originalThis;

    //This holds the state value.
    private int state;
    //The current value to return
    private string currentValue;

    public string Current
    {
        get 
        {
            return currentValue;
        }
    }
}

方法主体然后从原始方法移动到“关闭”内部的方法称为MoveNext的,它返回一个布尔,并实现IEnumerable.MoveNext。 任何当地人的任何访问都通过“本”路由,以及任何类成员的任何访问都是通过this.originalThis路由。

任何“回报收益率EXPR”被翻译成:

currentValue = expr;
state = //the state number of the yield statement;
return true;

任何产量break语句被翻译成:

state = -1;
return false;

还有就是在函数的最后一个“隐” yield break语句。 switch语句然后在自己看的状态数并跳转到相关标签的过程的开始介绍。

然后,将原来的方法被翻译成这样的:

IEnumerator<string> strings(IEnumerable<string> args)
{
   return new ClosureEnumerable(this,args);
}

该方法的状态都推入对象和MoveNext方法事实上使用switch语句/状态变量是什么让迭代器的行为的最后一个“收益率后立即返回,就像控制被传递回点“语句下一次‘的MoveNext’之称。

重要的是要指出,然而,由C#编译器使用的转型是不是要做到这一点的最好办法。 试图用“产量”与递归算法,当它从表现不佳受到影响。 还有是概括一种更好的方式,在这里做一个很好的文件:

http://research.microsoft.com/en-us/projects/specsharp/iterators.pdf

如果你还没有读过这是值得一读。



Answer 2:

只要看准了这一问题-我写了一篇文章最近就可以了。 我必须在这里补充提到,虽然在文章其他链接...



Answer 3:

雷蒙德陈回答了这个; http://blogs.msdn.com/b/oldnewthing/archive/2008/08/12/8849519.aspx

(编辑,以指向该系列的第1部分,而不是部分4)



文章来源: Algorithm for implementing C# yield statement