我有一个在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()':并非所有代码路径都返回值
为什么不在其他情况下抱怨?
这就是我上面所说的吗? 如果无法初始化资源,我们会崩溃,因此编译器会认为它无关紧要。
答案 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
块“吃掉”异常,导致它不再向上移动堆栈,编译器注意到没有路径返回值或异常。