Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/visual-studio-2010/4.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';s_C#_Goto - Fatal编程技术网

C# 可以用goto';s

C# 可以用goto';s,c#,goto,C#,Goto,我知道goto是一种糟糕的设计实践。但想象一下,我们被困在一个荒岛上,工具箱里除了gotos和ifs什么都没有。那么这不是: int i = 0; while (i < 10) i++; inti=0; 而(i

我知道goto是一种糟糕的设计实践。但想象一下,我们被困在一个荒岛上,工具箱里除了gotos和ifs什么都没有。那么这不是:

    int i = 0;
    while (i < 10) i++; 
inti=0;
而(i<10)i++;
与此相同:

    int i = 0;
    loop: if (i < 10) { i++; goto loop; }
inti=0;
循环:如果(i<10){i++;转到循环;}
?


在c语言中,仅仅使用条件逻辑、赋值/更改变量、方法调用和跳转,你就可以做任何你通常能做的事情,这难道不是真的吗?

是的,你可以重新编写任何程序,使其具有相同的输出,而不必使用任何循环。方法调用都可以内联,所以技术上也不需要这些调用。当然,类和接口对于任何逻辑都不是必不可少的。事实上,你可以用if,goto,赋值和加法来做任何事情。也许你甚至不需要那么多。

是的,这是可能的。最终,这就是组装的工作方式。在汇编中没有循环这样的东西。要更改代码中的位置,必须使用等价的“goto”(通常是
jmp
或某种形式的“branch”)或函数调用(如果存在)


然而,如果我继承的代码库使用了
goto
s,我要么从头重写它,要么在不允许的情况下退出。

从技术上讲?是的,绝对是。Goto程序是图灵完备的,因此你可以用它们来表示一切。最后,机器代码非常类似于goto程序,因为循环和其他操作都是使用条件跳转完成的。当然,在.NET中,您不能只使用goto。在某个时候,您会遇到这样的情况:要么使用其他不是这样编写的代码,要么语言结构迫使您执行其他操作(生成类、方法、函数等)。但从技术上讲,是的

你应该怎么做?绝对不是。Goto程序很难维护,当C#编译成中间语言时,中间语言使用跳转,但级别更高,这样做可能会损失大量性能。此外,虚拟机可以在“普通”代码中进行大量优化,而当您将虚拟机放在固定的goto模式中时,它无法进行优化

顺便说一句,您的原始代码编译成这个IL,这基本上是您使用goto(我的注释)编写的:

//i=0
IL_0001:ldc.i4.0//将整数值0加载到堆栈
IL_0002:stloc.0//i//将堆栈值存储在局部变量0中
//转到循环条件
IL_0003:br.s IL_0009//跳转到IL_0009
//循环开始:
//i=i+1
IL_0005:ldloc.0//i//将变量0加载到堆栈
IL_0006:ldc.i4.1//将整数'1'加载到堆栈
IL_0007:添加//添加最上面的两个堆栈值
IL_0008:stloc.0//i//将结果存储在局部变量0中
//循环条件:
//如果(i<10){goto循环开始}
IL_0009:ldloc.0//i//将变量0加载到堆栈
IL_000A:ldc.i4.s 0A//将整数'10'加载到堆栈
IL_000C:clt//比较最上面的两个堆栈值
IL_000E:stloc.1//CS$4$0000//将堆栈值存储在局部变量1中
IL_000F:ldloc.1//CS$4$0000//将变量1加载到堆栈
IL_0010:brtrue.s IL_0005//如果堆栈值为true,则跳转到IL_0005

转到
并不一定有什么本质上的不好。是什么原因使其不应被使用,如下所示:

  • 它极易被滥用,并且在正确使用时需要极大的控制;即使这样,它也会使代码更难阅读

  • 始终可以使用更具可读性的结构,如
    while
    do
    for
    foreach

因为同时使用其他东西总是可能的,而且总是更好,所以永远不应该实际使用
goto

我听说的一个可能的例外是打破了深嵌套:

for (int x = 0; x < 100; x++)
   for (int y = 0; y < 100; y++)
      for (int z = 0; z < 100; z++)
         if (condition)
            goto end;
end: ;
for(int x=0;x<100;x++)
对于(int y=0;y<100;y++)
对于(intz=0;z<100;z++)
如果(条件)
转到终点;
完:;
VS

for(int x=0;x<100,!条件;x++)
对于(int y=0;y<100,!条件;y++)
对于(intz=0;z<100,!条件;z++)

为了更直接地回答您的问题,是的,完全可以使用
goto
s而不是
while
s、
do
s等执行所有控制流。。。我甚至可能会建议,这对实践来说是一个很好的挑战,但在任何真正的代码中都不是,而且尝试在汇编中编码可能是一种更好的学习体验,而不是强迫自己使用
goto
s.

不。如果编程是这样的话,我宁愿辞职,做一个无家可归的人beggar@HighCore这是可能的。这就是组装的工作原理。它实用吗?“没有。”科尔约翰逊说得对。我的观点仍然站得住脚,尽管他们是平等的。但它也等于:
inti=10。如果您将自己限制为使用gotos模拟标准控制结构(而不是像意大利面条一样跳来跳去),那么代码的维护并不比使用正确的控制结构的代码困难。
for (int x = 0; x < 100; x++)
   for (int y = 0; y < 100; y++)
      for (int z = 0; z < 100; z++)
         if (condition)
            goto end;
end: ;
for (int x = 0; x < 100, !condition; x++)
   for (int y = 0; y < 100, !condition; y++)
      for (int z = 0; z < 100, !condition; z++)