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

喜你入骨 提交于 2019-12-25 10:57:13

问题


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");
    }
}

回答1:


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.

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.

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");
            }
        }
    }
}



回答2:


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.




回答3:


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://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/exceptions/exception-handling



来源:https://stackoverflow.com/questions/46267044/exception-in-catch-block-means-the-finally-block-never-executes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!