为什么编译器在这段代码中表现不同?

8
在C#中,以下方法将无法编译:
public bool IsItTrue()
{
}

编译器报错:'IsItTrue()': 没有所有的代码路径都返回一个值,这是非常合理的。但是下面的代码可以顺利编译。
public bool IsItTrue()
{
    while (true)
    {
    }
}

这段代码看起来有点不对,因为没有任何返回语句。为什么会这样呢?需要帮助……

3个回答

13
编译器知道第二个方法永远不会返回。
如果任何情况下这两种方法中的任一方法返回,则它们必须返回一个布尔值。
第一个方法不包含任何无限循环,不抛出任何无条件异常等,因此它必须返回一个布尔值。但是代码没有返回一个布尔值,所以编译器拒绝编译它。
第二个方法由于无限循环while (true)而永远不会返回。如果它永远不返回,则无论(如果有的话)返回什么都没有关系,所以编译器将允许它编译。
还有几个编译器会认可并允许的示例:
public bool IsItTrue()
{
    throw new Exception("Always thrown!");
}

public bool HowAboutThisOne()
{
    if ((46 - 3) < (27 * 9))
    {
        throw new Exception("Always thrown!");
    }
}

有趣的是编译器会允许那样做。我可以理解为什么它可以被允许,但我想知道它在现实生活中有什么用途。 - Eric Petroelje
我知道我们可能想要类似于 while(true) 的线程,但即使是线程也应该在某个时刻结束吧?那么如果编译器能够检测到这种情况,为什么它不会抛出错误指向无限循环呢? - uriDium
这是因为循环或条件表达式可以在编译时计算。请参见我的答案:https://dev59.com/vUrSa4cB1Zd3GeqPavic#1953368 - Steve Guidi

3
第一个错误很好地被编译器错误信息解释了。
第二个永远不会返回,因此永远不会返回任何值。
这不一样。在您的第一个示例中,该方法可能会返回而没有向调用者返回任何值->编译器错误。
第二个将永远不会返回(编译器足够聪明,它会发现您创建了一个无限循环)。它永远不会进入“好的,我到达了方法的结尾,不知道要返回什么”的状态。

1

停机问题指出,你通常无法确定一个程序是否会终止或永远运行。鉴于本主题中存在似乎违反这一原则的示例,我怀疑C#编译器正在对循环条件进行分析,以便将其简化为编译时常量。如果该常量评估为true,那么我们知道该循环永远不会终止。

例如,请考虑以下两个函数。

public bool NoError()
{
    while (true) { }
}

public bool Error()
{
    while (NoError()) { }
}

如所示,第一个函数不会生成编译时错误。然而,第二个函数会因为编译器无法评估函数调用NoError()的结果而产生错误。如果将NoError()修改为始终返回true,情况也是如此。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接