【问题标题】:How to catch all unhandled exceptions in WinForms application correctly如何正确捕获 WinForms 应用程序中所有未处理的异常
【发布时间】:2015-11-30 09:12:01
【问题描述】:

我想为我的 WinForms 应用程序中任何线程的所有未处理异常设置处理程序方法。我不自己创建任何应用程序域。

根据UnhandledException文档,我需要通过Application.SetUnhandledExceptionMode方法设置UnhandledExceptionMode.ThrowException模式来捕获主线程的异常:

在使用 Windows 窗体的应用程序中,未处理的异常 主应用程序线程导致 Application.ThreadException 事件 被抚养。如果处理此事件,则默认行为是 未处理的异常不会终止应用程序,尽管 应用程序处于未知状态。在这种情况下, 未引发 UnhandledException 事件。这种行为可以改变 通过使用应用程序配置文件,或使用 Application.SetUnhandledExceptionMode 方法将模式更改为 ThreadException 事件之前的 UnhandledExceptionMode.ThrowException 处理程序已连接。这仅适用于主应用程序 线。为未处理引发 UnhandledException 事件 其他线程中抛出的异常

因此,生成的代码将如下所示:

    public static void UnhandledExceptionEventHandler(object sender, UnhandledExceptionEventArgs e)
    {
        // ...
    }

    [STAThread]
    static void Main(string[] args)
    {
        Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledExceptionEventHandler);

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new MainForm(pathToCheck));
    }

没事吧?它会从任何线程(包括主线程、UI 线程和Task 类创建的所有线程)中捕获所有未处理的异常吗?我是否正确理解了文档?

是的,我在这里看到了this之类的问题,但我不明白为什么还要使用以下代码:

Application.ThreadException += new     
  ThreadExceptionEventHandler(ErrorHandlerForm.Form1_UIThreadException);

【问题讨论】:

  • 请参阅this answer,了解为什么还要处理 ThreadException。
  • @stuartd 根据这个链接,我也可以通过 SetUnhandledExceptionMode 方法强制 UI 线程异常,所以我真的不需要指定 ThreadException 处理程序。我说的对吗?
  • 第三方库可能会出现异常,所以总是建议处理ThreadException。
  • 不,ThreadException 的默认处理程序是 13 年前的一个不错的想法,它可以让 .NET 的新程序员有机会处理异常而不是死去尝试。那些日子已经过去了,期望用户在丑陋的对话框中旋转命运之轮在今天是非常不合理的。
  • @Hans Passant 所以我根本不用担心ThreadException

标签: c# .net winforms exception


【解决方案1】:

您应该订阅这两个事件。请注意,即使这样也不会自动捕获来自其他线程的所有内容。例如,当异步调用委托时,只有在调用EndInvoke时,异常才会传播到调用者线程。

    [STAThread]
    static void Main(string[] args)
    {
        AppDomain.CurrentDomain.UnhandledException +=
            (sender, args) => HandleUnhandledException(args.ExceptionObject as Exception);
        Application.ThreadException +=
            (sender, args) => HandleUnhandledException(args.Exception);
    }

    static void HandleUnhandledException(Exception e)
    {
        // show report sender and close the app or whatever
    }

【讨论】:

  • “你应该订阅这两个事件”——为什么? “只有在调用 EndInvoke 时,异常才会传播到调用者线程”——如果我根本不显式调用 EndInvoke 方法怎么办?
  • 为什么:因为它们捕获来自不同来源的异常。请参阅msdn.microsoft.com/en-us/library/… EndInvoke:通常您不必担心这一点,在已经工作的应用程序中,BeingInvokeEndInvoke 总是成对调用。否则,调用的结果也会丢失。见stackoverflow.com/questions/7492741/…
  • 我应该只在main 方法中设置ThreadException 吗?它会为所有未来的任务和线程启用此功能吗?
  • 如果你不使用多个AppDomains,那么是的,就足够了。
  • 如果使用多个AppDomains,我把Application.ThreadException放在哪里?
猜你喜欢
  • 2011-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-16
  • 2010-09-21
相关资源
最近更新 更多