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");
}
}
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.
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.
Therefore, this is not a .NET issue but it's a matter on how Windows reacts to exception dispatching.
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");
}
}
}
}