算法实现C#的yield语句 [英] Algorithm for implementing C# yield statement

查看:190
本文介绍了算法实现C#的yield语句的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很想弄明白自己,但我想知道的大致有什么算法转换与产量报表功能进入状态机枚举例如如何做C#把这个?

I'd love to figure it out myself but I was wondering roughly what's the algorithm for converting a function with yield statements into a state machine for an enumerator? For example how does C# turn this:

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;
}

当然的结果可能完全不同,这取决于原来的code。

Of course the result can be completely different depending on the original code.

推荐答案

您正在寻找的特定code样品涉及一系列的变换。 请注意,这是该算法的近似描述。编译器使用的实际名称,以及c它的确切$ C $生成可能会有所不同。然后想法是一样的,但是。

The particular code sample you are looking at involves a series of transformations. Please note that this is an approximate description of the algorithm. The actual names used by the compiler, and the exact code it generates may be different. Then idea is the same, however.

第一个转变是的foreach改造,其中改造这个code:

The first transformation is the "foreach" transformation, which transforms this code:

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

这个code:

into this code:

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

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

第二个转换发现在函数体中所有的收益return语句,分配一个号码给每个(状态值),并创建一个转到标号屈服之后。

The second transformation finds all the yield return statements in the function body, assigns a number to each (a state value), and creates a "goto label" right after the yield.

第三个转变升降机到一个对象中的所有局部变量和函数参数的方法体叫做闭包。

The third transformation lifts all the local variables and function arguments in the method body into an object called a closure.

由于code在你的榜样,这将类似于此:

Given the code in your example, that would look similar to this:

 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路由。

The method body is then moved from the original method, to a method inside "Closure" called MoveNext, which returns a bool, and implements IEnumerable.MoveNext. Any access to any locals is routed through "this", and any access to any class members is routed through this.originalThis.

任何收益回报expr的被翻译成:

Any "yield return expr" is translated into:

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

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

Any yield break statement is translated into:

state = -1;
return false;

还有就是在函数的最后一个隐yield break语句。 switch语句,然后在看起来在状态数,并跳转到相关的标签的过程的开始引入。

There is an "implicit" yield break statement at the end of the function. A switch statement is then introduced at the beginning of the procedure that looks at the state number and jumps to the associated label.

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

The original method is then translated into something like this:

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

,这一事实,该方法的状态都被推入一个对象和MoveNext方法使用switch语句/状态变量就是允许的迭代器行为,如果控制在最后之后立即被传递回点收益回报的声明,下一次MoveNext的之称。

The fact that the state of the method is all pushed into an object and that the MoveNext method uses a switch statement / state variable is what allows the iterator to behave as if control is being passed back to the point immediately after the last "yield return" statement the next time "MoveNext" is called.

重要的是要指出,然而,所使用的C#编译器转变不做到这一点的最好办法。从表现不佳试图用收益与递归算法,当它受到影响。有一个很好的文件,概述一个更好的方式来做到这一点的位置:

It is important to point out, however, that the transformation used by the C# compiler is not the best way to do this. It suffers from poor performance when trying to use "yield" with recursive algorithms. There is a good paper that outlines a better way to do this here:

<一个href="http://research.microsoft.com/en-us/projects/specsharp/iterators.pdf">http://research.microsoft.com/en-us/projects/specsharp/iterators.pdf

这是值得一读,如果你没有看过呢。

It's worth a read if you haven't read it yet.

这篇关于算法实现C#的yield语句的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆