Consider this program:
using System;
static class Program {
static void Main(string[] args) {
try {
try { throw new A(); }
finally { throw new B(); }
}
catch (B) { }
Console.WriteLine("All done!");
}
}
class A : Exception { }
class B : Exception { }
Here, an exception of type A is thrown for which there is no handler. In the finally block, an exception of type B is thrown for which there is a handler. Normally, exceptions thrown in finally blocks win, but it's different for unhandled exceptions.
When debugging, the debugger stops execution when A is thrown, and does not allow the finally block to be executed.
When not debugging (running it stand-alone from a command prompt), a message is shown (printed, and a crash dialog) about an unhandled exception, but after that, "All done!" does get printed.
When adding a top-level exception handler that does nothing more than rethrow the caught exception, all is well: there are no unexpected messages, and "All done!" is printed.
I understand how this is happening: the determination of whether an exception has a handler happens before any finally blocks get executed. This is generally desirable, and the current behaviour makes sense. finally blocks should generally not be throwing exceptions anyway.
But this other Stack Overflow question cites the C# language specification and claims that the finally block is required to override the A exception. Reading the specification, I agree that that is exactly what it requires:
- In the current function member, each
trystatement that encloses the throw point is examined. For each statementS, starting with the innermost try statement and ending with the outermost try statement, the following steps are evaluated:
- If the
tryblock ofSencloses the throw point and if S has one or morecatchclauses, the catch clauses are examined [...]- Otherwise, if the
tryblock or acatchblock ofSencloses the throw point and ifShas afinallyblock, control is transferred to thefinallyblock. If thefinallyblock throws another exception, processing of the current exception is terminated. Otherwise, when control reaches the end point of thefinallyblock, processing of the current exception is continued.- If an exception handler was not located in the current function invocation, the function invocation is terminated, and one of the following occurs:
- [...]
- If the exception processing terminates all function member invocations in the current thread, indicating that the thread has no handler for the exception, then the thread is itself terminated. The impact of such termination is implementation-defined.
An exception isn't considered unhandled, according to my reading of the spec, until after all function invocations have been terminated, and function invocations aren't terminated until the finally handlers have executed.
Am I missing something here, or is Microsoft's implementation of C# inconsistent with their own specification?