转到被视为有害的声明?

发布于 2024-08-26 08:06:41 字数 108 浏览 4 评论 0原文

如果上面的说法是正确的,那么为什么当我在 .Net BCL 上使用反射器时,我看到它被大量使用?

编辑:让我重新表述一下:我在反射器中看到的所有 GO-TO 都是由人类或编译器编写的吗?

If the statement above is correct, then why when I use reflector on .Net BCL I see it is used a lot?

EDIT: let me rephrase: are all the GO-TO's I see in reflector written by humans or compilers?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

栀梦 2024-09-02 08:06:41

我认为以下关于 Goto 的维基百科文章的摘录在这里特别相关:

可能是最著名的批评
GOTO 是 Edsger 于 1968 年写的一封信
Dijkstra 调用 Go To 语句
被认为是有害的。在那封信中
Dijkstra 认为不受限制的 GOTO
声明应被废除
高级语言,因为它们
使分析和分析任务变得复杂
验证程序的正确性
(特别是那些涉及循环的)。
提出了另一种观点
在唐纳德·高德纳 (Donald Knuth) 的《结构化》中
使用 go to 语句进行编程
分析了许多常见的编程
任务并发现其中一些
GOTO 是最佳语言结构
使用。

因此,一方面,我们有Edsger Dijkstra(一位非常有才华的计算机科学家)争论< em>反对使用GOTO语句,特别反对过度使用GOTO语句,理由是:这是一种不太结构化的代码编写方式。

另一方面,我们有 Donald Knuth(另一位非常有才华的计算机科学家)认为使用 GOTO,特别是明智地使用它实际上可以成为给定的程序代码片段的“最佳”和最优化的构造。

最终,恕我直言,我相信这两个人都是正确的。 Dijkstra 的观点是正确的,过度使用GOTO 语句肯定会降低一段代码的可读性和结构性,从纯理论角度看待计算机编程时确实如此。

然而,Knuth 也是正确的,因为在“现实世界”中,人们必须采取务实的方法,明智地使用 GOTO 语句确实可以成为最佳选择要使用的语言构造。

I think the following excerpt from the Wikipedia Article on Goto is particularly relevant here:

Probably the most famous criticism of
GOTO is a 1968 letter by Edsger
Dijkstra called Go To Statement
Considered Harmful. In that letter
Dijkstra argued that unrestricted GOTO
statements should be abolished from
higher-level languages because they
complicated the task of analyzing and
verifying the correctness of programs
(particularly those involving loops).
An alternative viewpoint is presented
in Donald Knuth's Structured
Programming with go to Statements
which analyzes many common programming
tasks and finds that in some of them
GOTO is the optimal language construct
to use.

So, on the one hand we have Edsger Dijkstra (a incredibly talented computer scientist) arguing against the use of the GOTO statement, and specifically arguing against the excessive use of the GOTO statement on the grounds that it is a much less structured way of writing code.

On the other hand, we have Donald Knuth (another incredibly talented computer scientist) arguing that using GOTO, especially using it judiciously can actually be the "best" and most optimal construct for a given piece of program code.

Ultimately, IMHO, I believe both men are correct. Dijkstra is correct in that overuse of the GOTO statement certainly makes a piece of code less readable and less structured, and this is certainly true when viewing computer programming from a purely theoretical perspective.

However, Knuth is also correct as, in the "real world", where one must take a pragmatic approach, the GOTO statement when used wisely can indeed be the best choice of language construct to use.

木森分化 2024-09-02 08:06:41

上面的内容并不完全正确 - 它是 Dijkstra 在 gotos 时使用的一种争论手段是唯一正在使用的流量控制结构。事实上,已经有几个人提出了反驳,包括 Knuth 的经典论文《StructuredProgrammingUsingGoto》(标题凭记忆)。在某些情况下(错误处理、状态机),goto 可以生成比“结构化”替代方案更清晰的代码(恕我直言)。

The above isn't really correct - it was a polemical device used by Dijkstra at a time when gotos were about the only flow control structure in use. In fact, several people have produced rebuttals, including Knuth's classic "Structured Programming Using Goto" paper (title from memory). And there are some situations (error handling, state machines) where gotos can produce clearer code (IMHO), than the "structured" alternatives.

離殇 2024-09-02 08:06:41

这些 goto 通常是由编译器生成的,尤其是在枚举器内部。
编译器总是知道她在做什么。

如果您发现自己需要使用 goto,您应该确保它是唯一的选择。大多数情况下,您会发现有更好的解决方案。

除此之外,在极少数情况下使用 goto 是合理的,例如使用嵌套循环时。同样,在这种情况下还有其他选择。您可以打破函数中的内部循环并使用 return 语句代替。您需要仔细查看额外的方法调用是否真的成本太高。


响应您的编辑:

不,并非所有 goto 都是编译器生成的,但其中很多是由编译器生成的状态机(枚举器)、switch case 语句或优化的 if else 结构产生的。只有少数情况下您才能判断是编译器还是原始开发人员造成的。您可以通过查看函数/类名称来获得良好的提示,编译器将生成“禁止”名称以避免与您的代码发生名称冲突。如果一切看起来正常并且代码尚未优化或混淆,则可能打算使用 goto。

These goto's are very often generated by the compiler, especially inside enumerators.
The compiler always knows what she's doing.

If you find yourself in the need to use goto, you should make sure it is the only option. Most often you'll find there's a better solution.

Other than that, there are very few instances the use of goto can be justified, such as when using nested loops. Again, there are other options in this case still. You could break out the inner loop in a function and use a return statement instead. You need to look closely if the additional method call is really too costly.


In response to your edit:

No, not all gotos are compiler generated, but a lot of them result from compiler generated state machines (enumerators), switch case statements or optimized if else structures. There are only a few instances you'll be able to judge whether it was the compiler or the original developer. You can get a good hint by looking at the function/class name, a compiler will generate "forbidden" names to avoid name clashes with your code. If everything looks normal and the code has not been optimized or obfuscated the use of goto is probably intended.

谎言月老 2024-09-02 08:06:41

请记住,您在 Reflector 中看到的代码是反汇编代码——Reflector 正在查看编译后的字节代码并尝试将原始源代码拼凑在一起。

因此,您必须记住,针对 goto 的规则适用于高级代码。用于替换 goto 的所有结构(forwhilebreakswitch< /code> 等)都使用 JMP 编译为代码。

因此,Reflector 像这样看待代码:

A:
    if !(a > b)
        goto B;
    DoStuff();
    goto A;
B:  ...

并且必须意识到它实际上被编码为:

 while (a > b)
    DoStuff();

有时读取的代码太复杂而无法识别模式。

Keep in mind that the code you are seeing in Reflector is a disassembly -- Reflector is looking at the compiled byte codes and trying to piece together the original source code.

With that, you must remember that rules against gotos apply to high-level code. All the constructs that are used to replace gotos (for, while, break, switch etc) all compile down to code using JMPs.

So, Reflector looks at code much like this:

A:
    if !(a > b)
        goto B;
    DoStuff();
    goto A;
B:  ...

And must realize that it was actually coded as:

 while (a > b)
    DoStuff();

Sometimes the code being read to too complicated for it to recognize the pattern.

溺深海 2024-09-02 08:06:41

Go To 语句本身并无害处,有时甚至非常有用。有害的是那些倾向于将其放在代码中不适当位置的用户。

Go To statement itself is not harmful, it is even pretty useful sometimes. Harmful are users who tend to put it in inappropriate places in their code.

回心转意 2024-09-02 08:06:41

当编译为汇编代码时,所有控制都会结构化并转换为(非)条件跳转。然而,优化器可能太强大了,当反汇编器无法识别跳转模式对应的控制结构时,就会发出始终正确的语句,即goto label;

这与goto 的危害性无关。

When compiled down to assembly code, all control structured and converted to (un)conditional jumps. However, the optimizer may be too powerful, and when the disassembler cannot identify what control structure a jump pattern corresponds to, the always-correct statement, i.e. goto label; will be emitted.

This has nothing to do with the harm(ful|less)ness of goto.

例如,双循环或许多嵌套循环(您已突破其中的循环)怎么样?

 foreach (KeyValuePair<DateTime, ChangedValues> changedValForDate in _changedValForDates)
            {
                foreach (KeyValuePair<string, int> TypVal in changedValForDate.Value.TypeVales)
                {
                    RefreshProgress("Daten werden geändert...", count++, false);

                    if (IsProgressCanceled)
                    {
                        goto TheEnd; //I like goto :)
                    }
                }
            }
TheEnd:

在这种情况下,您应该考虑使用中断来完成以下操作:

  foreach(KeyValuePair<DateTime, ChangedValues> changedValForDate in _changedValForDates)
    {
                    foreach (KeyValuePair<string, int> TypVal in changedValForDate.Value.TypeVales)
                    {
                        RefreshProgress("Daten werden geändert...", count++, false);

                        if (IsProgressCanceled)
                        {
                            break; //I miss goto :|
                        }
                    }

                 if (IsProgressCanceled)
                 {
                            break; //I really miss goto now :|
                 }//waaaAA !! so many brakets, I hate'm
    }

what about a double loop or many nested loops, of which you have break out, for ex.

 foreach (KeyValuePair<DateTime, ChangedValues> changedValForDate in _changedValForDates)
            {
                foreach (KeyValuePair<string, int> TypVal in changedValForDate.Value.TypeVales)
                {
                    RefreshProgress("Daten werden geändert...", count++, false);

                    if (IsProgressCanceled)
                    {
                        goto TheEnd; //I like goto :)
                    }
                }
            }
TheEnd:

in this case you should consider that here the following should be done with break:

  foreach(KeyValuePair<DateTime, ChangedValues> changedValForDate in _changedValForDates)
    {
                    foreach (KeyValuePair<string, int> TypVal in changedValForDate.Value.TypeVales)
                    {
                        RefreshProgress("Daten werden geändert...", count++, false);

                        if (IsProgressCanceled)
                        {
                            break; //I miss goto :|
                        }
                    }

                 if (IsProgressCanceled)
                 {
                            break; //I really miss goto now :|
                 }//waaaAA !! so many brakets, I hate'm
    }
初吻给了烟 2024-09-02 08:06:41

一般规则是您不需要使用goto。与任何规则一样,当然也有例外,但与任何例外一样,例外情况很少。

goto 命令就像毒品。如果仅在特殊情况下限量使用,那就很好。如果你一直使用太多,它会毁掉你的生活。

当您使用 Reflector 查看代码时,您看不到实际的代码。您看到的代码是根据编译器从原始代码生成的代码重新创建的。当您在重新创建的代码中看到 goto 时,并不确定原始代码中是否存在 goto。可能有一个更结构化的命令来控制流程,例如 breakcontinue,编译器以与 goto< 相同的方式实现/code>,这样 Reflector 就无法区分。

The general rule is that you don't need to use goto. As with any rule there are of course exceptions, but as with any exceptions they are few.

The goto command is like a drug. If it's used in limited amounts only in special situations, it's good. If you use too much all the time, it will ruin your life.

When you are looing at the code using Reflector, you are not seeing the actual code. You are seeing code that is recreated from what the compiler produced from the original code. When you see a goto in the recreated code, it's not certain that there was a goto in the original code. There might be a more structured command to control the flow, like a break or a continue which has been implemented by the compiler in the same way as a goto, so that Reflector can't tell the difference.

可爱暴击 2024-09-02 08:06:41

goto 被认为有害(人类使用但
对于计算机来说还可以)。

因为无论我们(人类)多么疯狂地使用 goto编译器总是知道如何阅读代码。

相信我...

使用 goto 阅读其他代码其中的 code> 很难。
阅读自己的带有 goto 的代码更加困难。

这就是为什么你看到它用于低级(机器语言)而不是高级(人类语言,例如 C#、Python...);)

goto considered harmful (for human to use but
for computers its okay).

because no matter how madly we(human) use goto, compiler always knows how to read the code.

Believe me...

Reading others code with gotos in it is HARD.
Reading your own code with gotos in it is HARDER.

That is why you see it used in low level (machine languages) and not in high level (human languages e.g. C#,Python...) ;)

沐歌 2024-09-02 08:06:41

“C 提供了无限滥用的 goto 语句和分支标签。从形式上来说,goto 从来都不是必需的,而在实践中,没有它几乎总是很容易编写代码。我们还没有使用 goto在这本书里。”

-- K&R(第二版):第 65 页

"C provides the infinitely-abusable goto statement, and labels to branch to. Formally, the goto is never necessary, and in practice it is almost always easy to write code without it. We have not used goto in this book."

-- K&R (2nd Ed.) : Page 65

心房的律动 2024-09-02 08:06:41

当我想执行终止操作时,我有时会使用 goto:

static void DoAction(params int[] args)
{
  foreach (int arg in args)
  {
    Console.WriteLine(arg);
    if (arg == 93) goto exit;
  }

  //edit:
  if (args.Length > 3) goto exit;
  //Do another gazillion actions you might wanna skip.

  //etc.
  //etc.

exit:
  Console.Write("Delete resource or whatever");
}

因此,我不是按 return,而是将其发送到执行另一个最终操作的最后一行,我可以从代码片段中的各个位置引用,而不是刚刚终止。

I sometimes use goto when I want to perform a termination action:

static void DoAction(params int[] args)
{
  foreach (int arg in args)
  {
    Console.WriteLine(arg);
    if (arg == 93) goto exit;
  }

  //edit:
  if (args.Length > 3) goto exit;
  //Do another gazillion actions you might wanna skip.

  //etc.
  //etc.

exit:
  Console.Write("Delete resource or whatever");
}

So instead of hitting return, I send it to the last line that performs another final action I can refer to from various places in the snippet instead of just terminating.

倒数 2024-09-02 08:06:41

在反编译的代码中,几乎所有您看到的 goto 都是合成的。不用担心他们;它们是如何在低级别表示代码的产物。

至于将它们放入您自己的代码中的正当理由吗?我能想到的主要问题是您使用的语言没有提供适合您正在解决的问题的控制结构;可以轻松创建自定义控制流系统的语言通常根本没有 goto 。完全避免使用它们也总是可能的,但是将任意复杂的代码重新排列到一个 while 循环和大量带有一整套控制变量的条件中......这实际上会使代码变得更加晦涩难懂(而且速度也较慢;编译器通常不够聪明,无法区分这种复杂性)。编程的主要目标应该是生成对计算机和阅读程序的人来说都清晰的程序描述。

In decompiled code, virtually all gotos that you see will be synthetic. Don't worry about them; they're an artifact of how the code is represented at the low level.

As to valid reasons for putting them in your own code? The main one I can think of is where the language you are using does not provide a control construct suitable for the problem you are tackling; languages which make it easy to make custom control flow systems typically don't have goto at all. It's also always possible to avoid using them at all, but rearranging arbitrarily complex code into a while loop and lots of conditionals with a whole battery of control variables... that can actually make the code even more obscure (and slower too; compilers usually aren't smart enough to pick apart such complexity). The main goal of programming should be to produce a description of a program that is both clear to the computer and to the people reading it.

陪你到最终 2024-09-02 08:06:41

有害与否,就看各人的喜好了。我个人不喜欢它们,并且发现它们在尝试代码的可维护性时效率很低。

现在,一件事是 goto 如何影响我们对代码的阅读,而另一件事是找到 goto 时抖动如何执行。来自 Eric Lippert 的博客,我想引用一下:

我们首先运行一次将循环转换为 goto 和标签。

因此,实际上编译器在发出 IL 时将几乎每个流控制结构转换为 goto/label 模式。当反射器读取程序集的 IL 时,它会识别该模式,并将其转换回适当的流控制结构。

在某些情况下,当发出的代码对于反射器来说太复杂而无法理解时,它只会向您显示使用标签和 goto 的 C# 代码,相当于它正在读取的 IL。例如,使用 yield returnyield break 语句实现 IEnumerable 方法时就是这种情况。这些类型的方法使用底层状态机转换为它们自己的实现 IEnumerable 接口的类。我相信在BCL你会发现很多这样的案例。

If it's harmful or not, it's a matter of likes and dislikes of each one. I personally don't like them, and find them very unproductive as they attempt maintainability of the code.

Now, one thing is how gotos affect our reading of the code, while another is how the jitter performs when found one. From Eric Lippert's Blog, I'd like to quote:

We first run a pass to transform loops into gotos and labels.

So, in fact the compiler transforms pretty each flow control structure into goto/label pattern while emitting IL. When reflector reads the IL of the assembly, it recognizes the pattern, and transforms it back to the appropriate flow control structure.

In some cases, when the emitted code is too complicated for reflector to understand, it just shows you the C# code that uses labels and gotos, equivalent to the IL it's reading. This is the case for example when implementing IEnumerable<T> methods with yield return and yield break statements. Those kind of methods get transformed into their own classes implementing the IEnumerable<T> interface using an underlying state machine. I believe in BCL you'll find lots of this cases.

娇纵 2024-09-02 08:06:41

如果没有如上所述过度使用,GOTO 可能会很有用。 Microsoft 甚至在 .NET Framework 本身的多个实例中使用它。

GOTO can be useful, if it's not overused as stated above. Microsoft even uses it in several instances within the .NET Framework itself.

沧笙踏歌 2024-09-02 08:06:41

这些 goto 通常由编译器生成,尤其是在枚举器内部。编译器总是知道她在做什么。

如果您发现自己需要使用 goto,您应该确保它是唯一的选择。大多数情况下,您会发现有更好的解决方案。

除此之外,很少有情况可以证明使用 goto 是合理的,例如使用嵌套循环时。同样,在这种情况下还有其他选择。您可以打破函数中的内部循环并使用 return 语句代替。您需要仔细查看额外的方法调用是否真的成本太高。

These goto's are very often generated by the compiler, especially inside enumerators. The compiler always knows what she's doing.

If you find yourself in the need to use goto, you should make sure it is the only option. Most often you'll find there's a better solution.

Other than that, there are very few instances the use of goto can be justified, such as when using nested loops. Again, there are other options in this case still. You could break out the inner loop in a function and use a return statement instead. You need to look closely if the additional method call is really too costly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文