当并非所有代码路径都返回时,C#编译器不会抱怨

时间:2017-01-13 16:34:48

标签: c# compiler-errors using

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

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

我刚注意到这一点,并将return块之外的using移到了最外层的函数范围,因为我觉得那就是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();
  }
}

确实编译器抱怨:

  

错误CS0161:`MainClass.f()':并非所有代码路径都返回值

为什么不在其他情况下抱怨?

这就是我上面所说的吗? 如果无法初始化资源,我们会崩溃,因此编译器会认为它无关紧要。

2 个答案:

答案 0 :(得分:5)

实际上是:

using(var objectName = <init-expression>) {
    //...
}

或多或少等同于:

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

所以它是try - finally - 阻止:如果在执行过程中出现问题,异常将被抛出该方法(主要是在finally部分完成之后)。

try - finally但是没有创建替代代码路径:如果try - 部分返回某些内容或引发错误,它将首先执行finally -part,但然后抛出异常或返回应该返回的内容。

答案 1 :(得分:4)

基本上,是的。 using语句会在堆栈中抛出异常。捕获异常并使用不返回的finally块意味着该方法既不会抛出异常也不会返回。

编译器也不会抱怨以下方法

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

为了扩展一点,因为我错过了一个编辑,其中catch块最初不在那里:

catch块“吃掉”异常,导致它不再向上移动堆栈,编译器注意到没有路径返回值或异常。