Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/305.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#是否为运行时分配了goto?_C#_.net_Goto - Fatal编程技术网

C#是否为运行时分配了goto?

C#是否为运行时分配了goto?,c#,.net,goto,C#,.net,Goto,我正在创建一个C#代码,其中我希望使用goto,但不希望使用编译时常量,即使用字符串作为标签标识符 顶部: 字符串label=“top”; //不起作用 后藤标签; //也不行 转到“顶端”; 我知道goto不是一个好的编程实践,这不是一个关于是否应该在应用程序中使用它的意见问题——这是一个从BASIC生成C代码的程序,它已经计算了goto。不,没有这样的问题。如果您真的需要,我可能会生成一个switch语句: switch (label): { case "top":

我正在创建一个C#代码,其中我希望使用goto,但不希望使用编译时常量,即使用字符串作为标签标识符

顶部:
字符串label=“top”;
//不起作用
后藤标签;
//也不行
转到“顶端”;

我知道
goto
不是一个好的编程实践,这不是一个关于是否应该在应用程序中使用它的意见问题——这是一个从BASIC生成C代码的程序,它已经计算了goto。

不,没有这样的问题。如果您真的需要,我可能会生成一个switch语句:

switch (label):
{
    case "top":
        goto top;
    case "bottom":
        goto bottom;
    // ...
}

如果您可以使用
字典
将代码分解为操作,那么这将是更干净的代码,可以在以后查看。。。但是如果你需要本地人在范围内等等,那么这个“讨厌的”代码可能是模仿基本行为的一种更简单的方法。

不,它没有

请注意,下面的C示例代码专门用作BASIC-to-C编译器的输出格式。任何编写这种“真实”C#代码的人都将被吊销编程许可证。

BASIC的GOTO语句可以使用“tail call pessimization”实现:将每个
GOTO X
转换为
GOSUB X:RETURN

然后,您可以将整个基本程序呈现为一个巨大的
Gosub(int-lineNumber)
函数,使用一个switch语句,每个行号都有一个
case
块,使用一个
Main
函数,只需将GOSUBs转换为最低行号即可

例如,基本程序:

10 PRINT "Enter an integer: ";
20 INPUT N%
30 IF N% MOD 2 = 0 THEN GOTO 60
40 PRINT N%;" is odd."
50 GOTO 70
60 PRINT N%;" is even."
70 PRINT "Goodbye."
可以逐行转换为C#程序,如下所示:

using System;

static class Program
{
    // BASIC variables are always global and zero-initialized.
    static int n_int = 0;

    static void Gosub(int lineNumber)
    {
        switch (lineNumber)
        {
            case 10: // 10 PRINT "Enter an integer: ";N%
                Console.Write("Enter an integer: ");
                // By default, the end of each line falls thru to next line number
                goto case 20;
            case 20: // 20 INPUT N%
                n_int = int.Parse(Console.ReadLine());
                goto case 30;
            case 30: // 30 IF N% MOD 2 = 0 THEN GOTO 60
                if (n_int % 2 == 0)
                {
                    Gosub(60);
                    return;
                }
                goto case 40;
            case 40: // 40 PRINT N%;" is odd."
                Console.WriteLine("{0} is odd.", n_int);
                goto case 50;
            case 50: // 50 GOTO 70
                Gosub(70);
                return;
            case 60: // 60 PRINT N%;" is even."
                Console.WriteLine("{0} is even.", n_int);
                goto case 70;
            case 70: // 70 PRINT "Goodbye."
                Console.WriteLine("Goodbye.");
                // Falling off the end of the program exits it.
                return;
        }
    }

    static void Main()
    {
        Gosub(10);
    }
}
using System;

static class Program
{
    // BASIC variables are always global and zero-initialized.
    static int n_int = 0;

    static void Gosub(int lineNumber)
    {
        START:
        switch (lineNumber)
        {
            case 10: // 10 PRINT "Enter an integer: ";N%
                Console.Write("Enter an integer: ");
                // By default, the end of each line falls thru to next line number
                goto case 20;
            case 20: // 20 INPUT N%
                n_int = int.Parse(Console.ReadLine());
                goto case 30;
            case 30: // 30 IF N% MOD 2 = 0 THEN GOTO 60
                if (n_int % 2 == 0)
                {
                    lineNumber = 60;
                    goto START;
                }
                goto case 40;
            case 40: // 40 PRINT N%;" is odd."
                Console.WriteLine("{0} is odd.", n_int);
                goto case 50;
            case 50: // 50 GOTO 70
                lineNumber = 70;
                goto START;
            case 60: // 60 PRINT N%;" is even."
                Console.WriteLine("{0} is even.", n_int);
                goto case 70;
            case 70: // 70 PRINT "Goodbye."
                Console.WriteLine("Goodbye.");
                // Falling off the end of the program exits it.
                return;
        }
    }

    static void Main()
    {
        Gosub(10);
        Console.ReadKey();
    }
}
当您有这样一个文字行号时,您可以优化
Gosub(X);返回转到<代码>转到案例X。但是,函数调用方法允许行号是任意表达式,而C#的
goto case
则不允许

转换后的代码显然不易维护,但它确实可以编译和运行

编辑:显然,C#编译器不能保证尾部调用优化,这可能会导致长循环或无限循环的堆栈溢出。但是,您可以通过重新分配
lineNumber
参数并跳回到
switch
语句的开头来手动执行此优化,如下所示:

using System;

static class Program
{
    // BASIC variables are always global and zero-initialized.
    static int n_int = 0;

    static void Gosub(int lineNumber)
    {
        switch (lineNumber)
        {
            case 10: // 10 PRINT "Enter an integer: ";N%
                Console.Write("Enter an integer: ");
                // By default, the end of each line falls thru to next line number
                goto case 20;
            case 20: // 20 INPUT N%
                n_int = int.Parse(Console.ReadLine());
                goto case 30;
            case 30: // 30 IF N% MOD 2 = 0 THEN GOTO 60
                if (n_int % 2 == 0)
                {
                    Gosub(60);
                    return;
                }
                goto case 40;
            case 40: // 40 PRINT N%;" is odd."
                Console.WriteLine("{0} is odd.", n_int);
                goto case 50;
            case 50: // 50 GOTO 70
                Gosub(70);
                return;
            case 60: // 60 PRINT N%;" is even."
                Console.WriteLine("{0} is even.", n_int);
                goto case 70;
            case 70: // 70 PRINT "Goodbye."
                Console.WriteLine("Goodbye.");
                // Falling off the end of the program exits it.
                return;
        }
    }

    static void Main()
    {
        Gosub(10);
    }
}
using System;

static class Program
{
    // BASIC variables are always global and zero-initialized.
    static int n_int = 0;

    static void Gosub(int lineNumber)
    {
        START:
        switch (lineNumber)
        {
            case 10: // 10 PRINT "Enter an integer: ";N%
                Console.Write("Enter an integer: ");
                // By default, the end of each line falls thru to next line number
                goto case 20;
            case 20: // 20 INPUT N%
                n_int = int.Parse(Console.ReadLine());
                goto case 30;
            case 30: // 30 IF N% MOD 2 = 0 THEN GOTO 60
                if (n_int % 2 == 0)
                {
                    lineNumber = 60;
                    goto START;
                }
                goto case 40;
            case 40: // 40 PRINT N%;" is odd."
                Console.WriteLine("{0} is odd.", n_int);
                goto case 50;
            case 50: // 50 GOTO 70
                lineNumber = 70;
                goto START;
            case 60: // 60 PRINT N%;" is even."
                Console.WriteLine("{0} is even.", n_int);
                goto case 70;
            case 70: // 70 PRINT "Goodbye."
                Console.WriteLine("Goodbye.");
                // Falling off the end of the program exits it.
                return;
        }
    }

    static void Main()
    {
        Gosub(10);
        Console.ReadKey();
    }
}

与前一个示例一样,常量
GOTO
目标可以优化为单个
GOTO case
语句。

它没有iti。我认为,通过使用函数字典,允许您按字符串值分派到某些代码,可以实现相同的行为。当然,在处理变量和其他问题时会遇到一些重大挑战。这真是个好主意,谢谢!您可以保留一个行号字典,然后跳转到行号,基本上就是计算出goto。如果你想发布答案,我会接受。BASIC只支持转到行号吗?如果是这样的话,也许有一个更简单的方法,比如Jon Skeet发布的答案。我在寻找你所说的Atari BASIC的gotos。在我心目中是辛克莱的基础,但我没有一个确切的规格连接。天才!我对这些的唯一想法是在块内的goto,比如说,在for/if中。我想如果你不允许跳出或跳入一个块,你可以在for循环的开关盒中有一个嵌套函数?好吧,一个
for
..
NEXT
循环可以很容易地转换成
WHILE
..
WEND
循环,然后可以将其转换为
GOTO
IF
GOTO
。仍然可能有一些奇怪的边缘情况跳入或跳出循环。好的,这导致了另一个问题。一个简单的程序,如10打印“你好”11转到10。(编译成一系列Gosub(10))由于大量递归导致StackOverflowException。我不确定这是否可以解决?有时,基本程序需要有无限循环,例如游戏。正如我在回答中提到的,如果基本的
GOTO
目标是常数,你总是可以将其优化为一个简单的
GOTO case
语句。只计算了需要调用
GOSUB
GOTO
(和
GOSUB
)。由于行号为BASIC的代码没有局部变量,堆栈帧将相对便宜。谢谢。我还意识到,如果使用/optimize运行csc,堆栈不会溢出。可能是因为您在编辑开始时提到的内容。不过,我想我还是会尝试优化自己的常量和无限goto调用,因为它们非常常见。