I frequently want to write finally code that does something slightly different if there was an exception thrown. Or put another way, I frequently want to write similar, but not identical, code in a catch block and a finally block. I end up having to do something such as:
bool finished = false;
try {
// do stuff
finished = true;
} finally {
// do stuff
if (!finished)
// do more stuff
}
Or such as:
Exception exception = null;
try {
// do stuff
} catch (Exception ex) {
exception = ex;
} finally {
// do stuff
if (exception != null)
// do more stuff
}
It would be nice if I could instead write:
try {
// do stuff
} finally (Exception ex) {
// ex is not null if and only if an exception was thrown
}
I would also be able to write:
try {
// do stuff
} finally (IOException ex) {
// ex is not null if and only if an IOException was thrown.
// ex is null if an exception other than IOException was thrown.
}
Can we just add a fault clause like the CLR supports? fault
is like finally but only executes if a try block does not exit normally. It evaluates after the catch block, but I do not know if you can reference exceptions caught in earlier blocks.
What are the use cases when you would find this useful?
bool finished = false; try { // do stuff finished = true; } finally { // do stuff if (!finished) // do more stuff }
why not
try {
// do stuff
// yep, it's finished
// do more stuff
} catch (...) {
// damn, it's not finished
} finally {
// well, anyways
}
if you want to know that the control reached a certain point perhaps you can use multiple/nested try catches.
I think its best to consider a method with many catch handlers...
try{
...
}
catch(ExceptionTypeA exa){
...
}
catch(ExceptionTypeB exb){
...
}
catch(ExceptionTypeC exc){
...
}
finally{
...
}
Now let's say I need to add logging to eventviewer on failure stating that the method just finished abnormally. I can either wire that logging code in each block, or do it as a set of exception filters but that's still me repeating the same code three times, I could use a bool finished
, but that's ugly.
This is the case for a fault block is for.
{
try { ... }
catch(Exception ex) when (Log(ex)) { throw; }
}
catch (Exception1) { ... }
catch (Exception2) { ... }
etc
OR
try { ... }
catch (Exception ex) when (Log(ex))
{
switch(ex)
{
case Exception1 ex1: ...;
case Exception2 ex2: ...;
default: throw;
}
}
That's still pretty ugly and introduces additional nesting. The CLR supports it, and actually can generate it in the case of using statements in asyc and iterator blocks.
Here is the case of how it would generate in an iterator block:
http://stackoverflow.com/a/16930005/468672
@mburbea
Depends. fault
handlers have no access to the thrown Exception
so their usefulness in a lot of those scenarios might be pretty limited.
For common exception handling scenarios I think that Java's approach might be cleaner:
try { ... }
catch (Exception1 | Exception2 ex) {
// common cleanup here
}
That doesn't really solve the problem that this proposal is trying to solve, but I don't think any out-of-the-box tools do. Having the finally
block accept an Exception
is novel as shorthand for the pattern demonstrated, but I think that the syntax accepting a derived exception would be confusing as it might imply that the finally block doesn't execute unless that exception is thrown, or that you can have multiple finally
blocks like you can catch
blocks.
@svick
With regard to use cases, I have ran into 3:
1. Finally code that cleans up slightly different when there's an exception
I've written many UI auto tests using Coded UI and a common design pattern is something like:
ShowDialog();
bool finished = false;
try {
// test code
finished = true;
} finally {
// cleanup code
if (finished)
ClickOK();
else
ClickCancel();
// more cleanup code
}
With this feature I could avoid the finished variable. While it's not a huge deal to do occasionally, with Coded UI at least you have to write such code a lot. I could see needing to do this in other situations where you frequently need to write complex finally code.
2. To deal with an exception that occurs within a finally block
By default an exception in a finally block would overwrite an existing exception (if there is one) which would virtually never be what you want.
Instead of having to do:
Exception ex1 = null;
try {
// do stuff
} catch (Exception ex) {
ex1 = ex;
} finally {
try {
// do more stuff
} catch (Exception ex2) {
if (ex1 == null)
rethrow;
else
throw new AggregateException(ex1, ex2);
}
}
With this proposed feature you could deal with this more cleanly by doing:
try {
// do stuff
} finally (Exception ex1) {
try {
// do more stuff
} catch (Exception ex2) {
if (ex1 == null)
rethrow;
else
throw new AggregateException(ex1, ex2);
}
}
3. Avoid having to rethrow an exception
To avoid the first shortcoming described in #14999, I frequently write code such as:
bool finished = false;
try {
// do stuff
finished = true;
} finally {
if (!finished)
// exception code (provided exception code doesn't reference the exception; exception will be rethrown)
}
to avoid having to do the following which can lose some call stack info:
try {
// do stuff
} catch (Exception) {
// exception code
throw;
}
With the proposed feature I could do the following, not lose any call stack info, and not have to have a finished variable:
try {
// do stuff
} finally (Exception ex) {
if (ex != null)
// exception code
}
Most helpful comment
Can we just add a fault clause like the CLR supports?
fault
is like finally but only executes if a try block does not exit normally. It evaluates after the catch block, but I do not know if you can reference exceptions caught in earlier blocks.