【问题标题】:Exception in catch block means the finally block never executes? [duplicate]catch 块中的异常意味着 finally 块永远不会执行? [复制]
【发布时间】:2018-02-26 06:25:32
【问题描述】:

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

【问题讨论】:

  • Visual Studio 通常会因异常而中断,然后您可以继续应用程序,只需再次按下小播放按钮即可。然后它实际上应该向您显示输出。
  • 顺序是: 1. 异常Apple被创建。 2、瞬间跳入下一个catch块(合身型)。 3. 异常 Banana 被创建。 4. finally 块运行。 5. 即时跳转到下一个 try/catch 块。 6. 所有 .NET 程序都隐含地包裹着一个 try...catch(Exception),唯一的操作是“通过对话框将其公开给用户”,然后只是关闭程序。在您的情况下,这是“下一个订单” Catchblock 将用于处理 Banana。
  • @PeterDuniho:只有最后一个副本可以解释这种行为——但它仍然没有。没有一个答案指出结果取决于用户操作。

标签: c# exception try-catch finally unhandled


【解决方案1】:

发生的原因和原因

结果取决于程序崩溃时单击的按钮。如果速度较慢,Windows 错误报告 (WER) 对话框将显示“调试”和“关闭程序”。如果您按下“关闭程序”按钮,该程序将被操作系统终止,而没有任何机会向控制台写入其他内容。

如果您足够快地点击“取消”按钮,则 Windows 错误报告部分将被取消,控制权将返回到您的程序。然后它将“Carrot”写入控制台。

因此,这不是 .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");
            }
        }
    }
}

【讨论】:

  • 我刚刚运行了一个类似的测试,该测试从带有 finally 块的函数中抛出未处理的异常,并且在 .NET Core 2.0 和 .NET Framework 4.6.1 中,finally 块在异常之后运行并且没有显示对话框。值得注意的是,我使用的是 Windows 10 版本 1803,所以也许 Windows 错误报告自您运行的任何版本以来都发生了变化?
  • @CameronBielstein:截图看起来很像 Windows 7。我想我在 Windows 10 上也试过了,因为我们在公司使用的是 Win10。答案来自 09/2017,因此从那时起我们可能至少有 2 次更新。建议:为改变的行为提出一个新问题,可能在此处链接或悬赏此问题,要求更新。以您的代表数量,第一种方法可能更可行。
【解决方案2】:

以下是正确引发和处理异常的一些规则。我发现对自己非常有用,并且喜欢在出现此类问题时将它们作为资源链接起来。我在您的示例代码和您的问题中看到了一些经典错误:

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 块中的另一个异常之后,在所有事情之后。异常处理只是一个主要由编译器强制执行的代码流。

【讨论】:

【解决方案3】:

你抛出了第二个异常,没有catch,第二个异常将不会继续代码..

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-24
    • 1970-01-01
    • 1970-01-01
    • 2013-08-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多