C# 是否可以始终消除goto';s

C# 是否可以始终消除goto';s,c#,goto,code-elimination,C#,Goto,Code Elimination,虽然使用goto的任何东西都很容易(如f.ex.IL所证明的),但我想知道是否也可以使用Java支持的所有东西消除所有具有更高级别表达式和语句的goto语句 或者,如果你愿意的话:我正在寻找的是“重写规则”,无论goto是以何种方式创建的,这些规则都会一直有效 这主要是一个理论问题,纯粹是兴趣问题;不是一个好的/坏的做法 我考虑过的一个显而易见的解决方案是使用如下内容: while (true) { switch (state) { case [label]: // her

虽然使用goto的任何东西都很容易(如f.ex.IL所证明的),但我想知道是否也可以使用Java支持的所有东西消除所有具有更高级别表达式和语句的goto语句

或者,如果你愿意的话:我正在寻找的是“重写规则”,无论goto是以何种方式创建的,这些规则都会一直有效

这主要是一个理论问题,纯粹是兴趣问题;不是一个好的/坏的做法

我考虑过的一个显而易见的解决方案是使用如下内容:

while (true)
{
    switch (state) {
       case [label]: // here's where all your goto's will be
          state = [label];
          continue;
       default:
          // here's the rest of the program.
    }
}
for(int i = 0; i < list.Count; i++)
{
    // some code that initializes inner
    bool conditon = false;
    for(int j = 0; j < inner.Count; j++)
    {
       // Some code that might change condition
       if (condition) break;
    }
    if (condition) break;
}
// Some more code.
虽然这可能会奏效,并且确实符合我的“正式”问题,但我一点也不喜欢我的解决方案。首先,它非常难看,其次,它基本上将goto封装到一个开关中,该开关的功能与goto完全相同

那么,有更好的解决方案吗


更新1

因为很多人似乎认为这个问题“太宽泛了”,所以我将进一步阐述。。。我提到Java的原因是因为Java没有“goto”语句。作为我的一个爱好项目,我试图将C#代码转换为Java,这被证明是相当具有挑战性的(部分原因是Java中的这种限制)

这让我思考。如果你有f.ex。在开放寻址中“remove”方法的实现(参见:-注1),在特殊情况下使用“goto”非常方便,尽管在这种特殊情况下,您可以通过引入“state”变量来重写它。请注意,这只是一个示例,我已经为continuations实现了代码生成器,当您尝试反编译它们时,它会生成大量的goto

我也不确定在这件事上重写是否总是会消除“goto”语句,以及是否在任何情况下都允许这样做。虽然我不是在寻找一个正式的“证据”,但一些证据表明在这件事上可以消除这种情况将是非常好的


因此,关于“广泛性”,我向所有认为有“太多答案”或“重写goto的很多方法”的人提出挑战,请提供一种算法或方法来重写一般情况,因为到目前为止,我找到的唯一答案就是我发布的答案。

我有一些实践经验,尝试采用一个非结构化程序(用COBOL语言编写),并通过删除GOTO的每个实例将其呈现为结构化。最初的程序员是经过改造的汇编程序员,虽然他可能知道PERFORM语句,但他没有使用它。是后藤后藤。这是很严肃的意大利面代码——几百行意大利面代码。我花了几个星期的空闲时间试图重写这个可怕的结构,最终我不得不放弃。那是一大堆疯狂的东西。但是它成功了!它的工作是以文本格式解析发送到大型机的用户指令,而且做得很好

所以,不,如果您使用手动方法,则不可能总是完全消除GOTO。然而,这是一个边缘案例——现有代码是由一个显然有着扭曲编程思维的人编写的。在现代,有一些工具可以解决以前难以解决的结构问题

从那天起,我就开始使用Modula-2、C、Basic、VB的三种风格和C#进行编码,从未发现需要甚至建议使用GOTO作为解决方案的情况。然而,对于最初的BASIC来说,GOTO是不可避免的。

这篇1994年的论文:提出了一种算法来消除C程序中的所有GOTO语句。该方法适用于任何用C#编写的程序,或任何使用诸如if/switch/loop/break/continue等公共结构的语言(好吧,但我不明白为什么它不会)

它从两个最简单的转换开始:

  • 案例1

    Stuff1();
    if (cond) goto Label;
    Stuff2();
    
    Label:
    Stuff3();
    
    变成:

    Stuff1();
    if (!cond)
    {
      Stuff2();
    }
    Stuff3();
    
    Stuff1();
    do
    {
      Stuff2();
      Stuff3();
    } while (cond);
    
  • 案例2

    Stuff1();
    Label:
    Stuff2();
    Stuff3();
    if (cond) goto Label;
    
    变成:

    Stuff1();
    if (!cond)
    {
      Stuff2();
    }
    Stuff3();
    
    Stuff1();
    do
    {
      Stuff2();
      Stuff3();
    } while (cond);
    
并在此基础上检查每一个复杂的情况,并应用迭代转换,从而导致这些琐碎的情况。然后用最终的gotos/labels消除算法结束

这是一本非常有趣的书

更新:关于该主题的其他一些有趣的论文(不容易获得,因此我在这里复制直接链接以供参考):


既然你说这是一个理论问题,下面是理论答案

Java是图灵完全的,所以当然,是的。您可以用Java表达任何C#程序。你也可以用雷舰红石号或扫雷舰来表达它。与这些备选方案相比,用Java表达它应该很容易


Patrice给出了一个显然更实用的答案,即进行转换的可理解算法。

一种可以避免跳转的情况,但我认为最好使用它:

当我需要退出内部循环和循环时:

for(int i = 0; i < list.Count; i++)
{
    // some code that initializes inner
    for(int j = 0; j < inner.Count; j++)
    {
       // Some code.
       if (condition) goto Finished;
    }
}
Finished:
// Some more code.
for(int i=0;i
要避免跳槽,您应该执行以下操作:

while (true)
{
    switch (state) {
       case [label]: // here's where all your goto's will be
          state = [label];
          continue;
       default:
          // here's the rest of the program.
    }
}
for(int i = 0; i < list.Count; i++)
{
    // some code that initializes inner
    bool conditon = false;
    for(int j = 0; j < inner.Count; j++)
    {
       // Some code that might change condition
       if (condition) break;
    }
    if (condition) break;
}
// Some more code.
for(int i=0;i
我觉得有了goto的声明看起来好多了

如果内部循环采用不同的方法,则第二种情况是可以的

void OuterLoop(list)
{
    for(int i = 0; i < list.Count; i++)
    {
        // some code that initializes inner
        if (InnerLoop(inner)) break;
    }
}
bool InnerLoop(inner)
{
    for(int j = 0; j < inner.Count; j++)
    {
       // Some code that might change condition
       if (condition) return true;
    }
    return false;
}
void OuterLoop(列表)
{
for(int i=0;i