Take this code:
using System;
namespace OddThrow
{
class Program
{
static void Main(string[] args)
{
try
{
The try-catch-finally blocks are working exactly as you expected if they are caught at some point. When I wrote a test program for this, and I use various nesting levels, the only case that it behaved in a way that matched what you described was when the exception was completely unhandled by code, and it bubbled out to the operating system.
Each time I ran it, the OS was what created the error message. So the issue is not with C#, it is with the fact that an error that is unhandled by user code is no longer under the control of the application and therefore the runtime (I believe) cannot force an execution pattern on it.
If you had created a windows form application, and wrote all your messages to a textbox (then immediately flushing them) instead of writing directly to the console, you would not have seen that error message at all, because it was inserted into the error console by the calling application and not by your own code.
EDIT
I'll try to highlight the key part of that. Unhandled exceptions are out of your control, and you cannot determine when their exception handler will be executed. If you catch the exception at some point in your application, then the finally
blocks will be executed before the lower-in-the-stack catch
block.