Reputation: 10199
I had a function that was returning in a using
block:
int f() {
using (...) {
...
return someVar;
}
}
I just noticed this and moved the return
outside of the using
block to the outermost function scope, because I felt that that's where the return
should be.
But I'm confused why the compiler wasn't complaining that not all code paths were returning. Is it simply because if it failed to initialize a resource, we would get a crash, so it doesn't matter?
Take this example:
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() { }
}
The compiler doesn't care that we only return in using
. However, I thought using
statements were basically syntactic sugar for try/catch
If we replace
using(A a = new A()) {
return 1;
}
with
A a = new A();;
try {
return 1;
}
catch (Exception e) { }
finally {
if (a != null) {
((IDisposable) a).Dispose();
}
}
Indeed the compiler complains:
error CS0161: `MainClass.f()': not all code paths return a value
Why doesn't it complain in the other case?
Is it simply what I said above? If it fails to initialize a resource, we would get a crash, so the compiler decides it doesn't matter.
Upvotes: 3
Views: 191
Reputation: 476574
Actually the:
using(var objectName = <init-expression>) {
//...
}
Is more or less equivalent to:
objectName = <init-expression>;
try {
//...
} finally {
objectName.Dispose();
}
So it is a try
-finally
-block: if something goes wrong during the execution, the exception will be thrown out of the method (mostly after the finally
part is done).
A try
-finally
however does not create an alternative code path: if the try
-part returns something or throws an error, it will first execute the finally
-part, but then either throw the exception or return what is ought to be returned.
Upvotes: 5
Reputation: 3551
Essentially, yes. The using
statement will throw it's exception up the stack. Catching the exception and using a finally block that doesn't return means that the method both doesn't throw an exception and doesn't return.
The compiler also doesn't complain about methods like the following
public int SuperCool(){
throw new NotImplementedException("bummer");
}
To expand a little since I missed an edit with the catch block not being there originally:
Having the catch
block "eats" the exception causing it to not move further up the stack and the compiler to notice that there is no path that returns a value or an exception.
Upvotes: 4