Exception in catch block means the finally block never executes?

1.9k views Asked by At

I have a simple try-catch-finally block in C#. As I understand it, the "finally" block is useful because its code will execute even if an exception is thrown inside the catch block (barring some special exception types).

However, in the simple example below, the finally block never executes. Visual Studio says an unhandled exception is occurring in my catch block and then the program terminates. I thought execution would just jump to the finally block instead.

How can I ensure the code in the finally block executes even when an exception occurs in the catch block?

public static void Main(string[] args)
{
    try
    {
        throw new Exception("Apple");
    }

    catch (Exception ex)
    {
        throw new Exception("Banana");
    }

    finally
    {
        // This line never executes. Why?
        Console.WriteLine("Carrot");
    }
}
3

There are 3 answers

2
Thomas Weller On BEST ANSWER

What and why it happens

The result depends on what button you click when the program crashes. If you're slow, the Windows Error Reporting (WER) dialog will show "Debug" and "Close program". If you press the "Close program" button, the program is terminated by the operationg system without any chance of writing something else to console.

Screenshot: close program

If you're fast enough to hit the "Cancel" button, then the Windows Error Reporting part will be cancelled and control goes back to your program. It will then write "Carrot" to the Console.

Screenshot: cancel

Therefore, this is not a .NET issue but it's a matter on how Windows reacts to exception dispatching.

How to get control over it

To disable the WER dialog, you can use WerAddExcludedApplication . To get rid of the Debug dialog, you can use SetErrorMode.

Please make yourself familiar with the disadvantages of using those methods. Read Raymond Chen's comments on WerAddExcludedApplication and check whether SetThreadErrorMode might be in favor.

Your code may then look like this:

using System;
using System.Runtime.InteropServices;

namespace ExceptionInCatch
{
    class Program
    {
        [DllImport("wer.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        static extern int WerAddExcludedApplication(String pwzExeName, bool bAllUsers);

        [Flags]
        public enum ErrorModes : uint
        {
            SYSTEM_DEFAULT = 0x0,
            SEM_FAILCRITICALERRORS = 0x0001,
            SEM_NOALIGNMENTFAULTEXCEPT = 0x0004,
            SEM_NOGPFAULTERRORBOX = 0x0002,
            SEM_NOOPENFILEERRORBOX = 0x8000,
            SEM_NONE = SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX
        }

        [DllImport("kernel32.dll")]
        static extern ErrorModes SetErrorMode(ErrorModes uMode);


        public static void Main(string[] args)
        {
            var executableName = AppDomain.CurrentDomain.FriendlyName;
            WerAddExcludedApplication(executableName, false);
            SetErrorMode(ErrorModes.SEM_NONE);
            try
            {
                throw new Exception("Apple");
            }
            catch (Exception ex)
            {
                throw new Exception("Banana");
            }
            finally
            {
                // This line will now execute
                Console.WriteLine("Carrot");
            }
        }
    }
}
1
Christopher On

Here are some rules for proper exception raising and handling. I found the highly usefull for myself, and like to link them as they as a resource when question like these come up. I see a number of the classical mistakes in your example code and indeed in your very question:

http://blogs.msdn.com/b/ericlippert/archive/2008/09/10/vexing-exceptions.aspx http://www.codeproject.com/Articles/9538/Exception-Handling-Best-Practices-in-NET

Finally blocks are always executed without a fail. Short of killing the entire process via the taskmanager, there is no way to skip them. They run after return, after another exception in a catch block, after everything. Exception handling is just a code flow that is largely enforced by the compiler.

0
Otávio Larrosa On

you're throwing an second exception, without catch, the second exception will not continue the code..

Unhandled Exception: System.Exception: Banana

I suggest you handle you're first exception and not thrown another.

static void Main(string[] args)
{
   var x = 2;
   try
   {
       if(x >1) throw new Exception("Apple");
   }
   catch (Exception ex)
   {
       x = 1;
   }
   finally
   {
      Console.WriteLine("Carrot");
   }
}

If you wanna know more about exception handling, RTFM: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/exceptions/exception-handling