【问题标题】:.NET compiler and "Not all code paths return a value".NET 编译器和“并非所有代码路径都返回值”
【发布时间】:2012-04-24 05:58:44
【问题描述】:

为什么在下面的代码中,.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.  

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

【问题讨论】:

  • 我猜开发人员觉得没有必要满足这样的代码。
  • 是否存在您看到此编译器错误的有用代码的实际 sn-p?
  • 但它仍然可以通过简单的重构来消除冗余。然后我怀疑它不会再触发错误。可以将其视为关注good design practice 的微妙推动。
  • 这个函数在它的当前状态是没用的,因为if (!test) return false 应该只是return false。我没有看到任何价值试图理解为什么一个无用的函数会引发警告/错误。
  • 回应您的编辑:dtb 的回答是正确的。 Eric Lippert 的文章不仅说“可达性分析器不是很聪明”,而且还说“语言设计的这个缺点很愚蠢,但坦率地说,我们比修复这个愚蠢的情况有更高的优先级。”这里的解决方案不是修复编译器;相反,它是删除if (!power_args_ok) 行。或者,您可以发送new Exception("power_args_ok is unexpectedly true") 以保护自己免受对该方法的错误编辑。

标签: c# compiler-construction compiler-errors


【解决方案1】:

让我直接回答您的问题,而不是详细说明。

  1. 函数的返回类型被指定为 Bool 因此 函数必须返回 True 或 false
  2. Param 已被定义为输入参数,因此它的值可以 编译时无法确定
  3. test 变量的值取决于参数并根据 step-2, param 值无法在编译时确定,因此 test 的值无法在编译时确定
  4. 由于 test 的值不称为编译时间(按照步骤 3) 因此它开始为 if (!test) 和 因此它会引发错误。

谢谢

【讨论】:

    【解决方案2】:

    让我们向后分析代码:

    问题:代码没有返回任何值。

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

    答案:就在最后一行。

    结论:所以那行代码(最后一行)应该总是返回一个值。

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

    答案:不,只有当testfalse 而它在第一行被设置为true 时才返回值。

    结论:正如编译器所说,这个函数从不返回值,而它应该返回bool

    【讨论】:

      【解决方案3】:

      来自 Visual Studio 2010 中包含的 C# 语言规范 4.0。

      10.6.10“方法体”:

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

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

      8.1 “端点和可达性”:

      如果一个语句可以通过执行到达,则该语句是 据说可以到达。相反,如果不可能 语句将被执行,该语句被称为不可达。

      ...

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

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

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

      【讨论】:

      • 嗯,我想这已经说明了。我只是很惊讶非常数表达式的深度分析为零。我可以理解分析可能会很快变得复杂,但奇怪的是编译器没有运行一些浅薄/琐碎的案例。
      • @Ricibob:可达性分析器做得越准确,规范就越难以清晰地描述它,因此您就越难知道您的程序是否正确。今天指定的语言试图占据算法易于理解的“最佳位置”,并捕获大多数可达性错误。尽量减少“误报”错误的数量在优先级列表中并不是很高。此外:错误为您指出了改进代码的机会;对此感到高兴!
      【解决方案4】:

      来自Eric Lippert's blog

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

      (博客文章是关于switch 语句的,但我猜可达性分析器对于if 语句并没有那么智能。)

      【讨论】:

        【解决方案5】:

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

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

        【讨论】:

          猜你喜欢
          • 2014-02-07
          • 1970-01-01
          • 2020-05-22
          • 2011-12-17
          • 1970-01-01
          相关资源
          最近更新 更多