【问题标题】:Not all code paths return a value - but they do并非所有代码路径都返回一个值 - 但它们确实
【发布时间】:2012-03-30 08:46:54
【问题描述】:

以下代码摘录无法编译,导致not code paths return a valueTest1StandardChargeCalculatorTest2StandardChargeCalculator 两种类型都派生自返回类型。

我知道如何解决这个问题,但我的问题是我为什么必须这样做? bool 是一个值类型 - 因此只能表示 truefalse,这两者都在这个 sn-p 中得到了满足。那么为什么编译失败呢?

internal StandardChargeCalculator Create()
{
      bool value = true;

      switch (value)
      {
          case true:
              return new Test1StandardChargeCalculator();
          case false:
              return new Test2StandardChargeCalculator();
      }
} //not all code paths return a value

【问题讨论】:

  • 你真的使用 switch 进行真假检查吗?
  • 我认为对于布尔值,这是一个有趣的问题,因为停止问题不适用于特殊情况。我的猜测:如果 switch 对某些情况有效,但不是对所有情况都有效(因为对于一般情况,无法解决停机问题),因此编译器开发人员选择了这种行为,因为打开 bool 并不是一个很大的问题用例。
  • @willDaBeast case 语句在块返回或抛出时不需要中断,因为这已经防止了失败。
  • Oded 的回答是正确的;我只想补充一点,我在 2009 年写了一篇关于这个案例的文章,以及 switch 语句的其他三个有趣的奇怪行为。你可以在这里阅读:blogs.msdn.com/b/ericlippert/archive/2009/08/13/…

标签: c# .net compiler-errors value-type


【解决方案1】:

当使用switch 语句时,编译器不理解当你使用布尔类型开启时只能有两个结果。

发生错误是因为您没有 default 案例。

不要使用 switch 进行布尔测试 - 使用 if 语句:

  bool value = true;

  if(value)
  {
      return new Test1StandardChargeCalculator();
  }

  return new Test2StandardChargeCalculator();

【讨论】:

  • 好吧,所以这基本上是因为短视的编译?
  • @m.edmondson 为什么要这样做?正如Eric Lippert 喜欢指出的那样,默认情况下功能是未实现的。
  • @m.edmondson - 近视?在我看来,在布尔值上进行开关就像是程序员错误。我会说编译器在这里做的是正确的事情。你当然可以只有一个case 和一个default - 这也应该可以解决错误(但是一个switch 和一个case 看起来有多傻?)。
  • @m.edmondson - 因为为布尔值添加特殊情况会使编译器复杂化一个不常见的用例并使行为与其他类型不一致。不要忘记这样的功能需要编写、测试、记录等,所有这些都需要成本。 Eric Lippert 写了关于 C# 团队如何决定一个特性是否加入的文章——我想说,在成本/收益分析中,这个特性会被列在列表中(特别是如果你同意 switch 在布尔值上的观点是错误
  • @EricLippert - 我没有意识到你是 Raymond 的旧东西的新东西;)
【解决方案2】:

您为什么认为编译器应该对特殊情况布尔值进行特殊处理并检测所有可能的值都有一个 case 语句?

如果您正在编写一个编译器,您会投入开发工作并通过实现它来增加错误的风险吗?

【讨论】:

  • 即一个不太可能的用例,实际上可能是程序中的一个错误:)
  • 我原则上同意,但开关不会使用编译器具有的任何正常数据流分析,并且数据流分析不会有布尔值的特殊情况吗?
【解决方案3】:

Absence of evidence is not evidence of absence Eric Lippert 中写到“证明”变量未赋值的局限性以及编译器在这方面的较弱目标:

我们不想证明 x 是未赋值的。 我们有兴趣证明 x 被赋值!如果我们可以 证明肯定,那么 x 是“肯定分配的”。如果我们不能 证明可以肯定地 x 是“未明确指定的”。

这并没有直接解释这个例子,但请注意它与:

int x;

if (a < 10) 
   x = 0;
else if (a >= 10)
   x = 1;

y = x; // x is 'unassigned'

我们可以很快看到x 将始终被分配,编译器甚至不会尝试找出。

【讨论】:

  • 我的一篇更好的文章可以链接到:blogs.msdn.com/b/ericlippert/archive/2009/08/13/…
  • @EricLippert,这些文章在网络存档之外的其他地方可用吗?我以为您已将 msdn 博客迁移到您自己的博客,但由于某种原因无法在那里找到第一个。第二个是ericlippert.com/2009/08/13/four-switch-oddities
  • @Qwertiy:感谢您的留言;我正在逐渐将所有旧内容移至 ericlippert.com,但进展缓慢;有将近十年的博客文章要迁移。
  • @EricLippert,我认为迁移是自动化的 :)
  • @Qwertiy:这是问题的很大一部分。微软自动将我的博客从一个博客平台迁移到另一个博客平台,以至于格式都被弄乱了,cmets 被删除了等等,这使得该过程难以进一步自动化。我正在浏览 Wayback Machine 上的原件,然后手动复制它们并重新格式化。
【解决方案4】:

据我了解,这与开关的定义不一致:

如果没有 case 表达式与 switch 值匹配,则控制权将转移到可选默认标签后面的语句。如果没有默认标签,则将控制权转移到交换机之外。

你是对的:应该没有编译器错误。所以,这可能是没有答案就是答案的情况。你将不得不忍受它。

    switch (answer)
    {
    ...
    default:
    return "It is as it is"
    }

【讨论】:

    【解决方案5】:

    也许更好的解决方案是

    internal StandardChargeCalculator Create()
    {
      StandardChargeCalculator result = null;
      bool value = true;
    
      switch (value)
      {
        case true:
          result = new Test1StandardChargeCalculator();
          break;
        case false:
          result = new Test2StandardChargeCalculator();
          break;
      }
      return result;
    }
    

    【讨论】:

    • 更好的解决方案是使用 if... 使用 switch 来测试布尔值是没有意义的
    • 我知道,但是对于不同的情况 - switch 是更好的解决方案,并且您想使用默认值来检查异常,例如,您可以使用这种方法。而且它只有 1 个回报 - 阅读起来更简单
    • 这是否也缺少break
    • If, else 是检查布尔值的最佳选择,这只会使代码比实际更难读
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-14
    • 1970-01-01
    • 1970-01-01
    • 2011-12-17
    • 1970-01-01
    相关资源
    最近更新 更多