catch块中的异常意味着finally块永远不会执行?

时间:2017-09-17 17:45:12

标签: c# exception try-catch finally unhandled

我在C#中有一个简单的try-catch-finally块。据我所知,“finally”块很有用,因为即使在catch块中抛出异常,它的代码也会执行(除非有一些特殊的异常类型)。

但是,在下面的简单示例中,finally块永远不会执行。 Visual Studio说我的catch块中发生了未处理的异常,然后程序终止。我认为执行只会跳转到finally块。

即使catch块中发生异常,如何确保finally块中的代码执行?

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 个答案:

答案 0 :(得分:1)

它发生的原因和原因

结果取决于程序崩溃时单击的按钮。如果您变慢,Windows错误报告(WER)对话框将显示" Debug"和"关闭程序"。如果按"关闭程序"按钮,程序由operationg系统终止,没有任何机会向控制台写入其他内容。

Screenshot: close program

如果你足够快,可以点击"取消"按钮,然后Windows错误报告部分将被取消,控制权将返回到您的程序。然后它将编写" Carrot"到控制台。

Screenshot: cancel

因此,这不是.NET问题,而是Windows如何对exception dispatching做出反应的问题。

如何控制它

要禁用WER对话框,您可以使用WerAddExcludedApplication 。要删除“调试”对话框,可以使用SetErrorMode

请熟悉使用这些方法的不足之处。阅读Raymond Chen's comments on WerAddExcludedApplication 并检查SetThreadErrorMode是否可能有利。

您的代码可能如下所示:

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 :(得分:0)

以下是适当的异常提升和处理的一些规则。我发现这对我自己非常有用,并且当这些问题出现时,喜欢将它们作为资源链接起来。我在你的示例代码中看到了许多经典错误,确实存在于你的问题中:

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

最后,块总是在没有失败的情况下执行。如果没有通过任务管理器杀死整个过程,就无法跳过它们。它们在返回之后运行,在一个catch块中的另一个异常之后运行。异常处理只是一个主要由编译器强制执行的代码流。

答案 2 :(得分:-1)

你引发第二个异常,没有捕获,第二个异常将不会继续代码..

Unhandled Exception: System.Exception: Banana

我建议你处理你的第一个例外而不是另一个例外。

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

如果您想了解有关异常处理的更多信息,请转发:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/exceptions/exception-handling