C#中标签的用途是什么?

C#中标签的用途是什么?,c#,C#,标签和转到被认为是不好的做法,据我所知,没有理由在C#中使用它 C#中标签的用途是什么?标签和goto本身没有什么问题。问题是人们倾向于滥用它们,这确实造成了问题 标签的典型用法 OperationStart: if ( !TrySomeOperation() ) { if ( MaybeFixOperation() ) { goto OperationStart; } } 您需要做出一些不能命中Infite循环的断言,但是给出一组合理的保证,这段代码没有

标签和转到被认为是不好的做法,据我所知,没有理由在C#中使用它


C#中标签的用途是什么?

标签和goto本身没有什么问题。问题是人们倾向于滥用它们,这确实造成了问题

标签的典型用法

OperationStart:
  if ( !TrySomeOperation() ) {
    if ( MaybeFixOperation() ) { 
      goto OperationStart;
    }
  }

您需要做出一些不能命中Infite循环的断言,但是给出一组合理的保证,这段代码没有本质上的错误

仅仅因为它们是一种声名狼藉的做法,并不意味着应该关闭使用它们的任何可能性。虽然它们可能永远不会被要求,但它们有时是最好的选择。

我认为这是一个营销决策


微软希望所有类型的开发人员都能使用他们的C语言,如果你添加标签,这会使一些程序员的转换更容易。它还使将旧代码移植到他们的语言变得更容易…

我在某个地方读到,在大多数情况下,goto应该只用于向前跳转,因此很可能只用于早期循环终止和继续外部循环,因为C#中没有标记的循环(与Java不同)。还有一些算法可以用goto优雅地表达,而不是用结构化的方式

有时一个位置恰当的“goto”比其他技术更优雅/可读。在不需要的时候到处放“goto”肯定是一种不好的做法。和往常一样,每种情况都应该仔细判断

例如,“当你的函数需要在失败的情况下进行清理时,goto’s可以很好。在函数末尾放置一个标签,在那里进行清理,然后在出现故障时“转到”它


然而,“goto”在C中的用处不如在C中。例如,在某些情况下,正确使用异常处理可以避免“goto”的需要。

标签的使用是为了支持
goto
。虽然
goto
可能很糟糕,但是如果您的语言中有
goto
,那么您需要标签。如果没有
goto
,标签在C#中确实是无用的。

当您实现一个小型的应用程序时,您可以对每个状态使用标签,对状态转换使用goto。这是植入有限状态机的标准方法之一,如果代码注释指向的文档中有状态机图,则可以生成清晰的代码

有时,问题域包含许多状态机(例如,电信协议通常由有限状态机定义),大多数情况下,您不会经常看到有限状态机


goto和标签对于机器生成的代码也非常有用,如果你正在编写一个输出C的简单编译器,你可能会非常高兴。没有goto的标签是无用的,它们什么也做不了

使用
goto
被认为是一种不好的做法。但有一种情况是不可避免的:打破嵌套循环:

foreach(...) {
  foreach(...) {
    if(...) {
      goto OuterLabel;
    }
  }
}
OuterLabel:

在这种情况下,使用
break
语句只会中断最内部的循环。

如果没有它们,很难使用switch语句。

虽然原则上我相信
goto
语句有合法的用途,实际上,自从C#首次发布以来,我一直在用它进行开发,直到现在我才知道它有一个
goto
语句。

代码生成器有时使用标签和goto。在某些情况下,它可以简化代码生成逻辑。由于可读性的原因,Goto语句通常是不被使用的,但是如果代码不打算被读取,那么这是一个没有实际意义的问题

我还看到过反编译器被IL和输出goto语句而不是人类想象的精心编制的指令序列弄糊涂的情况。如果goto语句是不合法的,那么反编译程序可能必须完全执行该段代码。通过这种方式,它至少可以生成一些可以往返的东西。

如果(publications.LikesGoTo==true) { 后藤; } 其他的 { 后藤;
}为什么会在那里?

原因其实很简单。汇编程序和IL不支持高级指令,如
for
do
break
continue
while
。隐式地,循环(或更一般地说:分支)的代码被编译成分支
goto
label
是一个非常字面的分支

请注意,如果没有“goto”,您就无法轻松实现我所能想到的所有装置,即使通常有更好的替代方案(在这一点上,我想指出,有一些设计模式,如
状态模式

若你们设计了一种像C#这样的语言,这是一种“IL的高级汇编程序”,那个么至少支持IL中的所有东西才有意义。这里,branch/label是低级构造,而goto/label是C#投影(将范围添加为高级构造)

来自编译器POV

最后,如果你深入了解编译器的工作原理,那么可预测的代码和不可预测的代码是有区别的。编译器的优化部分花费了大量精力来规范化代码中使用的结构。一旦规范化,它将使用模式进行优化

问题就在这里。如果您有一个
while
循环、一个
for
循环或一个
foreach
循环,它肯定会生成一个规范化模式。毕竟,循环是代码中可以优化的第一件事。但是,如果您使用的是奇怪的分支,它们将不会被优化——这仅仅是因为它不会被规范化为标准化的模式,因此模式匹配器不会选择它

这条评论不仅仅是关于代码模式的可预测性——它还涉及数据流的可预测性。同样,如果它是可预测的,编译器可以比