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不支持高级指令,如for
, do
, break
, continue
和while
。 隐式地,循环(或更一般地说:分支)的代码被编译为分支。 goto
和label
是一个非常字面的分支。
请注意,如果没有’goto’,你根本无法实现我能够轻松想到的所有装置 – 尽管通常有更好的选择(此时我想指出有像State pattern
模式这样的设计模式)。
如果你设计一种类似C#的语言,它是“IL的高级汇编程序”,那么至少支持IL中的所有内容是有意义的。 这里,branch / label是低级构造,goto / label是C#projection(范围被添加为高级构造)。
来自编译器POV
最后,如果你了解编译器的工作原理,那么可预测的代码和不可预测的代码就会有所不同。 编译器的优化部分花费了大量精力来规范您在代码中使用的构造。 一旦标准化,它就使用模式进行优化。
这就是问题所在。 如果你有一个while
循环,一个for
循环或一个foreach
循环,它肯定会生成一个规范化的模式。 毕竟,循环是代码中可以优化的第一件事。 但是,如果您使用的是奇怪的分支,它们将不会被优化 – 只是因为它不会被标准化为标准化模式,因此不会被模式匹配器拾取。
这个评论不只是关于代码模式的可预测性 – 它还涉及数据流的可预测性。 同样,如果它是可预测的,那么你的编译器可以做得更多,而不是它。 在各种情况下,像break
和continue
这样的结构也会导致更多不可预测的分支; 标签和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 ; }