Exception in catch block means the finally block never executes? [duplicate]
Asked Answered
H

3

0

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");
    }
}
Hamon answered 17/9, 2017 at 17:45 Comment(3)
Visual Studio usually breaks on an Exception and then you can continue the app, you just press the little play button again. Then it should actually show you the output.Debera
The the order is: 1. Exception Apple is created. 2. Instant jump into the following catch block (fitting type). 3. Exception Banana is created. 4. Finally block runs. 5. Instant jump to the next try/catch block. 6. All .NET Programms implicitly have a try...catch(Exception) wrapped around them, with the only action being "expose it to the user via a Dialog" and the just closing the programm. In your case that is the "next order" Catchblock taht will ahve to deal with Banana.Lipson
@PeterDuniho: Only the last duplicate might explain the behavior - and still it doesn't. None of the answers point out that the result depends on a user action.Littles
L
5

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");
            }
        }
    }
}
Littles answered 17/9, 2017 at 19:5 Comment(2)
I just ran a similar test that throws an unhandled exception from a function with a finally block and in both .NET Core 2.0 and .NET Framework 4.6.1 the finally block is run after the exception and no dialog is shown. It's worth noting that I'm on Windows 10 version 1803, so perhaps Windows Error Reporting has changed since whatever version you were running?Papoose
@CameronBielstein: Screenshots look much like Windows 7. I think I tried it on Windows 10 as well, since we use Win10 in the company. Answer is from 09/2017, so we probably have at least 2 Updates since then. Suggestions: ask a new question for the changed behavior, probably linking here or put a bounty on this question asking for an update. With your amount of rep, the first approach is probably more feasible.Littles
L
0

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.

Lipson answered 17/9, 2017 at 19:15 Comment(1)
What OP provides is a minimal reproducible example, not real code. The "number of classical mistakes" are intended to make the code as short as possible.Littles
B
-1

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

Bouchier answered 17/9, 2017 at 18:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.