今天早些时候,当我在编写一个方法时,我突然意识到我不确定为什么我要实现的习惯用法会编译。如果将其他一切都抽象出来,它将如下所示:
private int Example()
{
while (true)
{
if (some condition)
{
return 1;
}
}
}您有一个显式的无限循环,以及循环中的一些条件集,这些条件会导致循环以return语句结束。让我们暂时忽略我这样做的原因,而不是检查while子句中的终止条件,因为答案是复杂和无关的--我想知道的是,为什么编译器不用“并非所有路径都返回值”来标记这一点。错误,因为严格地说并不是所有的路径都返回值。while循环从未进入的情况(当然,从未发生过)不会返回任何内容。
现在,有两个原因我可以想象它会发生:这是由于其他原因而发生的优化的副作用,或者这种情况是由编译器显式地处理以允许这种习惯用法。我的直觉是这可能是第一个案例。举个例子,我一点也不惊讶,这段代码编译如下:
private int Example2()
{
if (true) return 1;
}因为编译器在if中看到了一个常量true,并优化了条件。不过,我真的不明白为什么这会“修复”第一个示例。
哦,更奇怪的是,如果进行了一些消除循环的优化,则会编译以下代码:
private int Example3()
{
while (true)
{
if (false)
{
return 1;
}
}
}我认为整个内部循环会被优化掉,去掉所有有效的返回。在字节码/编译器级别上到底发生了什么,使这一切变得有意义?
发布于 2011-09-07 00:46:59
编译器不会对此进行标记,因为方法的末尾是不可访问的。这不是问题-只有当你可以在不返回值的情况下到达方法的末尾(右大括号)时才是问题。
这不是编译器优化的问题,而是遵循规范中规定的可达性定义的情况。
请注意,您根本不需要return语句……这段代码是无用的,但却非常有效:
public int EndlessLoop()
{
while (true)
{
}
}发布于 2011-09-07 07:13:19
要为您提供这类无限循环的用例,请考虑以下代码:
public int KeyboardChecker()
{
while (true)
{
if (KeyHasBeenPressed())
{
HandleKeyPress();
}
}
}然后,您可以在其自己的线程上运行此方法,从而异步处理键盘输入(这是轮询模式,具有适当的事件系统通常更可取)。
您可以想象线程在完成时返回状态代码,因此该方法的返回值为int。但是,由于这个特定的线程永远不会结束,所以该方法不包含任何返回语句根本不是问题。C#设计者知道这些用例,并使上述方法合法化。
请注意,确定特定方法是否总是返回值的一般问题是无法确定的(即,任何计算机程序都无法解决)。因此,C#编译器可能会抱怨总是返回值的代码(尽管它永远不会接受不返回值的程序):
public int DoWork()
{
// The compiler doesn't figure out this will always be true.
if (((int)Math.Sqrt(4)) == 2)
{
return 3;
}
// And therefore complains that not all code paths return a value for this method.
}https://stackoverflow.com/questions/7323326
复制相似问题