标签和GOTO
被认为是不好的做法,据我所知,没有理由在C#中使用它。
C#中标签的用途是什么?
答案 0 :(得分:20)
标签和goto本身没有任何问题。问题是人们倾向于滥用它们确实会产生问题。
标签的典型用途
OperationStart:
if ( !TrySomeOperation() ) {
if ( MaybeFixOperation() ) {
goto OperationStart;
}
}
你需要做一些你无法触及infitite循环的断言,但是给出一套合理的保证,这段代码没有任何内在错误。
答案 1 :(得分:8)
仅仅因为他们是一个声名狼借的做法,并不意味着应该关闭使用它们的任何可能性。虽然他们可能永远不会需要,但偶尔也是最好的方式。
答案 2 :(得分:6)
当您实现较小的finite state machine时,您可以为每个州使用标签,并使用 goto 进行状态转换。这是植入有限状态机的标准方法之一,并且可以导致清晰的代码,前提是代码注释指向的文档中有状态机图。
有时问题域包含许多状态机(例如电信协议通常由有限状态机定义),大多数情况下你经常看不到有限状态机。
Gotos 和标签对于机器生成的代码也非常有用,如果您正在编写一个输出C#的简单编译器,您可能会对它们感到非常高兴。
答案 3 :(得分:3)
代码生成器有时会使用标签和gotos。在某些情况下,它可以简化代码生成逻辑。由于可读性原因,Goto语句通常被避开,但如果不打算读取代码那么这是一个有争议的问题。
我还看到过反编译器被IL充分混淆并输出goto语句而不是人类会想到的精心设计的指令序列的情况。如果goto语句不合法,那么反编译器可能不得不完全放弃该段代码。这样,至少,它可以生成可以往返的某事。
答案 4 :(得分:2)
我认为这是一个营销决策..
Microsoft希望各种开发人员使用他们的C#语言,如果添加标签,它会让一些程序员更容易转换。它还可以更容易地将旧代码移植到他们的语言中......
答案 5 :(得分:2)
没有goto
的标签没用,它们什么都不做。
使用goto
被认为是一种不好的做法。但有一种情况是无法避免的:打破嵌套循环:
foreach(...) {
foreach(...) {
if(...) {
goto OuterLabel;
}
}
}
OuterLabel:
在这种情况下,使用break
语句只会破坏最内层循环。
答案 6 :(得分:2)
为什么会出现?
原因其实很简单。汇编程序和IL不支持高级指令,如for
,do
,break
,continue
和while
。隐式地,循环(或更一般地说:分支)的代码被编译为分支。 goto
和label
是一个非常直接的分支。
请注意,如果没有'goto',你根本无法实现我能够轻松想到的所有装置 - 尽管通常有更好的选择(此时我想指出有类似{的设计模式{1}})。
如果你设计一种类似C#的语言,它是“IL的高级汇编程序”,那么至少支持IL中的所有内容是有意义的。这里,branch / label是低级构造,goto / label是C#projection(范围被添加为高级构造)。
来自编译器POV
最后,如果您了解编译器的工作原理,可预测的代码和不可预测的代码会有所不同。编译器的优化部分花费了大量精力来规范您在代码中使用的构造。一旦标准化,它就会使用模式进行优化。
这就是问题所在。如果您有State pattern
循环,while
循环或for
循环,它肯定会生成标准化模式。毕竟,循环是代码中可以优化的第一件事。但是,如果您使用的是奇怪的分支,那么将不会进行优化 - 只是因为它不会被标准化为标准化模式,因此不会被模式匹配器拾取。< / p>
此评论不仅涉及代码模式的可预测性 - 它还涉及数据流的可预测性。同样,如果它是可预测的,那么你的编译器可以做得更多,而不是它。在各种情况下,像foreach
和break
这样的结构也会导致更多不可预测的分支;标签和continue
将让您更轻松地到达那里。结果是一样的:如果发生这种情况,你的表现会受到影响。
因此,所有编译器确实将循环更改为特定表单的分支。 IL编译器是一个SSA编译器,就像LLVM一样。钱德勒的这段视频解释了一两件关于它是如何工作的:https://www.youtube.com/watch?v=FnGCDLhaxKU
答案 7 :(得分:1)
如果没有它们,很难做出切换语句。
答案 8 :(得分:0)
我在某处读过,在大多数情况下,goto应该只用于向前跳转,因此很可能仅用于早期循环终止和继续外循环,因为C#中没有标记循环(与Java不同)。并且有一些算法可以用goto优雅地表达,而不是以结构化的方式表达。
答案 9 :(得分:0)
有时候,'goto'比其他技术更优雅/可读。把'goto'放在不需要的地方当然是一种不好的做法。一如既往,应仔细判断每种情况。
例如,当你的函数需要进行清理以防万一它失败时,'goto'会很好。在函数的末尾放置一个标签,在那里进行清理,然后在发生故障时“转到”它。
尽管如此,'goto在C#中的用处不如在C中。例如,在某些情况下,正确使用异常处理可以避免使用'goto'。
答案 10 :(得分:0)
使用标签是为了支持goto
。 goto
可能不正确,如果您的语言中有goto
,那么您需要标签。如果没有goto
,标签在C#中确实无用。
答案 11 :(得分:0)
虽然原则上我认为goto
语句有合法用途,但实际上我一直在使用C#进行开发,因为它首次发布,我不知道有到目前为止goto
声明。
答案 12 :(得分:0)
if(audience.LikesGoTo == true) { 转到LabelThatSupportGoTo; } 其他 { 转到LabelForRejectGoTo; }