C#编译器不会在未所有代码路径都有返回值时报错

3

我有一个函数,它在一个 using 块中返回:

int f() {
  using (...) {
     ...
     return someVar;
  }
}

我刚刚注意到这个问题,并将return移到了最外层函数作用域之外,因为我认为那里应该放置return

但我很困惑为什么编译器没有抱怨不是所有的代码路径都有返回值。难道这只是因为如果它未能初始化资源,我们会崩溃,所以这并不重要吗?

看这个例子:

class MainClass {
  public static void Main (string[] args) {
    f();
  }

  public static int f() {
    using(A a = new A()) {
      return 1;
    }
  }
}

class A : IDisposable{
  public void Dispose() { }
}

编译器并不在意我们只在using中返回。然而,我认为using语句基本上是try/catch的语法糖。
如果我们替换
using(A a = new A()) {
  return 1;
}

使用

A a = new A();;
try  {
  return 1;
}

catch (Exception e) { }
finally {
  if (a != null) {
    ((IDisposable) a).Dispose();
  }
}

确实,编译器报错:

error CS0161: `MainClass.f()': not all code paths return a value

为什么在另一个情况下不会报错呢?

是因为我之前说的吗?如果无法初始化资源,我们将会崩溃,所以编译器认为这并不重要。


7
这只是一个 try-finally 的语句块,没有 catch。如果你在代码中删除了 catch,就不会出现编译错误。 - juharr
1
@pushkin:但是你可以在“using”块中定义局部变量,但不能在外部访问。基本上,“using”旨在使代码更易读(它将处理构造的对象,无论你在哪里返回)。 - Willem Van Onsem
1
@pushkin 这意味着您现在需要更改变量的范围,使其也在 using 之外,即使从概念上讲,在该上下文之外它们永远没有意义。而且从概念上讲,您仍然面临与从 using 内部返回相同的情况,即现在需要证明当 using 运行时变量肯定已经被分配,这是一个与证明 using 具有返回值使方法的终点不可达的问题相同的问题。 - Servy
1
@EricLippert 当我研究这个奇怪的问题时(我是C#新手),我偶然看到了关于try/finally的参考资料,但我可能没有仔细阅读。我看到了try/finally,但由于很少见到不带catchtry,所以我可能让自己相信我实际上看到了try/catch。我确实看到了使用try/finally而不是using的示例,但由于我从未使用过不带catchtry/finally语句,因此我盲目地期望如果try/catch/finally导致编译错误,那么try/finally也会导致编译错误。 - pushkin
1
@pushkin:谢谢!了解人们如何过度概括等内容,在设计新的语言特性时非常有帮助。 - Eric Lippert
显示剩余4条评论
2个回答

5
实际上,这个:
using(var objectName = <init-expression>) {
    //...
}

基本上相当于:

objectName = <init-expression>;
try {
    //...
} finally {
    objectName.Dispose();
}

所以,这是一个try-finally块:如果在执行过程中出现问题,则异常将从方法中抛出(在finally部分完成后)。
然而,try-finally并不创建另一条代码路径:如果try部分返回某些内容或引发错误,它将首先执行finally部分,但随后会抛出异常或返回应该返回的内容。

4

基本上是这样的。 using语句将抛出异常。捕获异常并使用一个不返回任何内容的finally块意味着该方法既不会抛出异常也不会返回值。

编译器对以下方法也不会报错:

public int SuperCool(){
   throw new NotImplementedException("bummer");
}

为了补充一下,因为我错过了一个编辑,当时没有写catch块:
拥有catch块会“吃掉”异常,导致它不会向上移动堆栈,并且编译器会注意到没有返回值或异常的路径。

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