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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With