C# 摆脱';收益率';在(通过转换为状态机)递归生成器方法中? 我有一个优美、优美的代码,我想把它移植到其他语言,比如C++、java等。

C# 摆脱';收益率';在(通过转换为状态机)递归生成器方法中? 我有一个优美、优美的代码,我想把它移植到其他语言,比如C++、java等。,c#,state-machine,yield-return,C#,State Machine,Yield Return,我面临的问题有两个: 代码使用yield 代码是高度递归的 手动去除产量是可能的,但非常繁琐——这个过程非常机械,显然是可以自动化的。 同时,C#编译器将其翻译成的状态机非常难看——它实际上无法用于移植。(我试过反编译它,只是不可读。) 我想知道,除了花上几天的时间来手动消除收益率,我还有其他选择吗? 或者是否有某种工具可以将产生的块转换为(可读的)状态机,然后我可以像普通代码一样进行移植 如果你想知道我所说的“高度递归”是什么意思——下面的代码基本上就是代码的结构(实际只有66行;它不是

我面临的问题有两个:

  • 代码使用
    yield
  • 代码是高度递归的
手动去除
产量
是可能的,但非常繁琐——这个过程非常机械,显然是可以自动化的。
同时,C#编译器将其翻译成的状态机非常难看——它实际上无法用于移植。(我试过反编译它,只是不可读。)

我想知道,除了花上几天的时间来手动消除
收益率
,我还有其他选择吗?
或者是否有某种工具可以将
产生的
块转换为(可读的)状态机,然后我可以像普通代码一样进行移植


如果你想知道我所说的“高度递归”是什么意思——下面的代码基本上就是代码的结构(实际只有66行;它不是一个非常长的函数):

静态IEnumerable MyRecursiveYielder(args)
{
如果(blah1)收益返回foo;
否则如果(blah2)
foreach(foo2.Blah()中的变量foo1)
foreach(MyRecursiveYielder(moreArgs)中的var项)
收益回报项目;
其他的
{
var state=新状态();
foreach(blah中的var项)
foreach(MyRecursiveYielder中的变量项2(其他参数))
foreach(blah3中的var项目3)
{
foreach(MyRecursiveYielder(yetMoreArgs)中的var结果)
收益结果;
foobar1();
}
while(条件)
foreach(无意义的var foo)
foreach(MyRecursiveYielder(argh)中的var结果)
{
如果(条件2)
foreach(在MyRecursiveYielder中的var结果(几乎不存在)))
收益结果;
foobar2();
}
}
}

yield实现的功能与co例程非常接近。您应该能够移植到支持这些功能的语言。不幸的是,很少有语言能做到这一点。我相信艾达有

下一步是纤维。Win32 API公开了光纤,因此对于C++来说,这是一种选择。我想对Java来说不是


因此,简短的回答是:调查目标平台的协同例程或光纤的可用性。

我想我找到了一个解决方案:在大多数情况下,我可以使用LINQ。这样,我就不需要在前几个案例中产生任何东西,因为这些案例不是有状态的

有状态的收益率(即最后一个收益率)是问题所在,但在仔细考虑之后,我意识到我的“有状态的”
yield
code基本上只是树搜索(确切地说是广度优先搜索)。基本上就像代码一样

因此,我可以简单地创建自己的
IEnumerable
类,该类执行广度优先搜索——也就是说,给定一个传递函数
(T parenet)=>(IEnumerable children)
,它将一个接一个地输出子项,并继续搜索,直到没有剩余项


如果这样做行得通的话,那么就可以去掉所有的
yield
s,同时保持代码结构基本不变——使其更可读,更易于移植。

Oof。对象创建混乱。您最好在这里管理自己的堆栈,而不是进行递归。我在别处发布了一个答案来说明我的意思:你需要按需运行还是可以提前运行?在我看来,最明显的解决办法是,每次你做一个收益率,就把这些放在一个列表中,然后再返回。当然,这一切都在记忆中,看看你正在循环的东西的数量可能会相当大。。。否则,庞大而笨重的状态机听起来可能是解决方案。反编译的状态机以何种方式因兴趣而无法读取?这只是一个需要清理的例子,这样不同的反编译器可能会使它看起来更好,还是结构本身是一件坏事?@Chris:如果我可以按需运行它会更好,懒洋洋的——我不知道输出有多大(可以是从零到无限数量的项)。。。所以我不能总是把结果放在一个列表中(尽管有时我可以)。不过,如果其他一切都失败了,这是一种选择。关于不可读取性——当我反编译它时,它有568行,有很多类似于
g_uinitlocal24
的标识符等等。当然还有后藤。我这样写的全部原因是它短小而优雅。。。这就是为什么我现在被卡住了…:\@斯彭德:哈哈,是的。。。问题是,将普通递归函数转换为迭代函数并不像将递归生成器转换为迭代状态机那么糟糕,尽管。。。一想到我会怎么做我就头疼!(但据我所知,我没有更好的解决方案……)可能会引起兴趣。而且,这不是一个理想的解决方案,但听起来比我要尝试的要好,谢谢+1这没有什么意义,Linq的可移植性远不如收益率。至少不是因为LINQ使用了非常严重的收益。@ HaSSPAANTAN:这也是我最初想到的,但是有两个对应点:(1)C++,至少,具有Boo.Load,并且(2)端口LINQ类的存在是非常容易的,而不是为了理解这个代码的迭代版本。尽管如此,我还没有做到这一点,我可能仍然会遇到一些我没有预见到的问题\
static IEnumerable<ReturnType> MyRecursiveYielder(args)
{
    if (blah1) yield return foo;
    else if (blah2)
        foreach (var foo1 in foo2.Blah())
            foreach (var item in MyRecursiveYielder(moreArgs))
                yield return item;
    else
    {
        var state = new State();
        foreach (var item in blah)
            foreach (var item2 in MyRecursiveYielder(otherArgs))
                foreach (var item3 in blah3)
                {
                    foreach (var result in MyRecursiveYielder(yetMoreArgs)))
                        yield return result;
                    foobar1();
                }
        while (condition)
            foreach (var foo in blah)
                foreach (var result in MyRecursiveYielder(argh)))
                {
                    if (condition2)
                        foreach (var result in MyRecursiveYielder(almostThere)))
                            yield return result;
                    foobar2();
                }
    }
}