.NET 编译器和“并非所有代码路径都返回值”

本文关键字:路径 代码 返回值 编译器 NET | 更新日期: 2023-09-27 18:30:43

为什么在下面的代码中,.NET 编译器无法确定所有代码路径都返回一个值?

bool Test(bool param) {
    bool test = true;
    if (param)
        test = false;
    else
        test = false;
    if (!test)
        return false;
}

错误 CS0161:并非所有代码路径都返回值!

代码可以重构 - 但编译器并不建议这样做。 然而,所有返回路径都被覆盖了 - 那么为什么编译器抱怨它们没有呢?

编辑:我想这里的结论是:

(error CS0161) + (all code paths obviously return a value) => refactor code.  

一旦你养成了翻译的习惯,我想一切都很好。

.NET 编译器和“并非所有代码路径都返回值”

来自 Visual Studio 2010 附带的 C# 语言规范 4.0。

10.6.10 "方法主体":

当方法的返回类型不为 void 时,每个 return 语句 该方法的主体必须指定隐式表达式 可转换为返回类型。的方法主体的终结点 值返回方法不得访问。换句话说,在 值返回法,控制不允许流出端 的方法主体。

可访问性的定义在这里(强调):

8.1 "终点和可达性":

如果可以通过执行访问语句,则该语句为 说是可以到达的。相反,如果不可能 语句将被执行,该语句被称为无法访问。

要确定特定语句或端点是否可访问, 编译器根据可达性执行流分析 为每个语句定义的规则。流动分析考虑因素 控制行为的常量表达式 (§7.19) 的值 语句,但非常量表达式的可能值 不被考虑

由于!test不是一个常量表达式(即使它总是计算结果为true),编译器有义务在流分析中不考虑它。此限制的一个原因(也许是唯一原因)是,在一般情况下,执行这种流分析是不可能的。

若要消除该错误,您需要在 else 子句中或无条件地在方法末尾使用另一个 return 语句。

来自 Eric Lippert 的博客:

可达性分析器不是很智能。它没有意识到只有两种可能的控制流,并且我们已经用返回覆盖了所有这些控制流。

(这篇博客文章是关于switch语句的,但我想可达性分析器对于if语句来说并不聪明。

这只是表示编译器在初始化什么和将执行哪些行方面的智能程度的限制。

我不时会遇到这种情况。但这很少是一个问题。我通常会稍微重组代码。

让我们向后分析代码:

问题:代码不返回任何值。

问:在代码中的什么位置返回值?

答:就在最后一行。

结论:因此,该行代码(最后一行)应始终返回一个值。

问:最后一行总是返回一个值吗?

答:否,仅当test设置为在第一行truefalse时才返回值。

结论:正如编译器所说,这个函数在应该返回bool时永远不会返回值。

与其详细介绍,不如让我直接回答你的问题。

  1. 函数的返回类型指定为 Bool,因此函数必须返回 True 或 false
  2. 参数
  3. 已被定义为输入参数,因此其值可以在编译时不确定
  4. 测试变量的值取决于参数,并且根据步骤2,参数值不能在编译时确定,因此测试值不能在编译时确定
  5. 由于测试值不知道编译时(按照步骤-3)因此,它开始为 if (!test) 和因此它会抛出错误。

谢谢