5

I wrote simple C# console app:

class Mystery
{
    static void Main(string[] args)
    {
        MakeMess();
    }

    private static void MakeMess()
    {
        try
        {
            System.Console.WriteLine("try");
            throw new Exception(); // let's invoke catch
        }
        catch(Exception)
        {
            System.Console.WriteLine("catch");
            throw new Exception("A");
        }
        finally
        {
            System.Console.WriteLine("finally");
            throw new Exception("B");
        }
    }
}

The output given in console is:

try

catch

Unhandled Exception: System.Exception: A at Mystery.Program.MakeMess() in ...

It seems that CLR caught A and the finally block was not invoked at all.

But when I surround call to MakeMess() with try-catch block:

static void Main(string[] args)
{
    try
    {
        MakeMess();
    }
    catch(Exception ex)
    {
        System.Console.WriteLine("Main caught " + ex.Message);
    }
}

The output looks totally different:

try

catch

finally

Main caught B

It seems that Exception that propagates from MakeMess() is different when Exception is strictly handled outside of method.

What's the explanation of this behavior?

Community
  • 1
  • 1
elklepo
  • 509
  • 4
  • 17
  • What happens if you run this outside the compiler? I assume that the finally will be written – TheLethalCoder May 05 '17 at 10:36
  • 2
    See http://stackoverflow.com/a/1555578/613130 *one important note is that if e is not caught by a try/catch block further up the call stack or handled by a global exception handler, then the finally block may never execute at all.* – xanatos May 05 '17 at 10:36
  • you didn't catch exception inside catch. program stops. no reason to continue when something totally failed. In your seconds example its same as having nested try catches. the outer try will catch exception of inner catch. but before that finally will be invoked. – M.kazem Akhgary May 05 '17 at 10:36
  • More or less duplicate of http://stackoverflow.com/q/1555567/706456 – oleksii May 05 '17 at 10:37
  • @TheLethalCoder Exactly, "finally" is printed after "UnhandledException(...)" but nothing about **B** thrown after "finally". – elklepo May 05 '17 at 10:41
  • @Klepak Probably because it has already caught an unhanded exception and doesn't want to deal with multiple of them. – TheLethalCoder May 05 '17 at 10:44

2 Answers2

5

The behavior you are seeing has nothing to do with a finally block throwing or not. You simply have an unhandled exception in your application, when that happens, all bets are off, including if finally blocks run or not:

From MSDN documentation:

Within a handled exception, the associated finally block is guaranteed to be run. However, if the exception is unhandled, execution of the finally block is dependent on how the exception unwind operation is triggered. That, in turn, is dependent on how your computer is set up. For more information, see Unhandled Exception Processing in the CLR.

Usually, when an unhandled exception ends an application, whether or not the finally block is run is not important. However, if you have statements in a finally block that must be run even in that situation, one solution is to add a catch block to the try-finally statement. Alternatively, you can catch the exception that might be thrown in the try block of a try-finally statement higher up the call stack. That is, you can catch the exception in the method that calls the method that contains the try-finally statement, or in the method that calls that method, or in any method in the call stack. If the exception is not caught, execution of the finally block depends on whether the operating system chooses to trigger an exception unwind operation.

If the finally block must run, then the solution is to do precisely what you've done in the second snippet: handle the unhandled exception.

Community
  • 1
  • 1
InBetween
  • 32,319
  • 3
  • 50
  • 90
-2

What happens if a finally block throws an exception? :

C# 4 Language Specification § 8.9.5: If the finally block throws another exception, processing of the current exception is terminated.

I think that finally block is for cleanig resources only and should not throw any exceptions.

Community
  • 1
  • 1
Ivan Maslov
  • 168
  • 2
  • 13