C#中的标签有什么用?

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

C#中的标签有什么用?

标签和goto本身没有任何问题。 问题是人们倾向于滥用它们确实会产生问题。

标签的典型用途

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

你需要做一些你无法触及infitite循环的断言,但是给出一套合理的保证,这段代码没有任何内在错误。

仅仅因为它们是一个声名狼借的做法,并不意味着应该关闭任何使用它们的可能性。 虽然它们可能永远不会被要求 ,但它们偶尔也是最好的方式。

当您实现一个小型有限状态机时,您可以为每个状态使用标签转到状态转换。 这是植入有限状态机的标准方法之一,并且可以导致清晰的代码,前提是代码注释指向的文档中有状态机的图表。

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

Gotos标签对于机器生成的代码也非常有用,如果你正在编写一个输出C#的简单编译器,你可能会很高兴。

我认为这是一个营销决策..

微软希望各种开发人员使用他们的C#语言,如果你添加标签,它会让一些程序员更容易过渡。 它还可以更容易地将旧代码移植到他们的语言中…

没有goto标签是没用的,它们什么都不做。

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

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

在这种情况下,使用break语句只会破坏最内层的循环。

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

我还看到了反编译器被IL充分混淆并输出goto语句而不是人类会想到的精心设计的指令序列的情况。 如果goto语句不合法,那么反编译器可能必须完全解决该部分代码。 这样,至少,它可以生成可以往返的东西

为什么会这样?

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

请注意,如果没有’goto’,你根本无法实现我能够轻松想到的所有装置 – 尽管通常有更好的选择(此时我想指出有像State pattern模式这样的设计模式)。

如果你设计一种类似C#的语言,它是“IL的高级汇编程序”,那么至少支持IL中的所有内容是有意义的。 这里,branch / label是低级构造,goto / label是C#projection(范围被添加为高级构造)。

来自编译器POV

最后,如果你了解编译器的工作原理,那么可预测的代码和不可预测的代码就会有所不同。 编译器的优化部分花费了大量精力来规范您在代码中使用的构造。 一旦标准化,它就使用模式进行优化。

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

这个评论不只是关于代码模式的可预测性 – 它还涉及数据流的可预测性。 同样,如果它是可预测的,那么你的编译器可以做得更多,而不是它。 在各种情况下,像breakcontinue这样的结构也会导致更多不可预测的分支; 标签和goto将让您更轻松地到达那里。 结果是一样的:如果发生这种情况,您的表现将受到影响。

因此,所有编译器确实将循环更改为特定表单的分支。 IL编译器是一个SSA编译器,就像LLVM一样。 钱德勒的这段video解释了一两件关于它是如何工作的: https : //www.youtube.com/watch?v = .FnGCDLhaxKU

没有它们很难做转换语句。

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

有时,放置良好的’goto’比其他技术更优雅/可读。 把’goto’放在不需要的地方当然是一种不好的做法。 一如既往,应仔细判断每种情况。

例如,当你的函数需要进行清理以防万一它失败时,’goto’会很好。 您在function的末尾放置一个标签,在那里进行清理,然后在发生故障时“转到”它。

尽管如此,’goto在C#中的用处变得不如在C中。例如,在某些情况下,正确使用exception处理可以避免使用’goto’。

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

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

如果(audience.LikesGoTo == true){goto LabelThatSupportGoTo ; } else {goto LabelForRejectGoTo ; }