有没有办法在 WinForms .NET 3.5 应用程序中为未处理的异常定义操作?

Posted

技术标签:

【中文标题】有没有办法在 WinForms .NET 3.5 应用程序中为未处理的异常定义操作?【英文标题】:Is there a way to define an action for unhandled exceptions in a WinForms .NET 3.5 app? 【发布时间】:2008-09-30 19:33:34 【问题描述】:

注意,我知道这个问题已经解决了here。那篇文章讨论了 .NET 1.1 中的异常处理,同时暗示 >.NET 2.0 有更好的解决方案,所以这个问题专门针对较新的 .NET 版本。

我有一个 Windows 窗体应用程序,预计它会频繁且意外地失去与数据库的连接,在这种情况下,它会将自身重置为其初始状态。

我已经通过自定义 DBWrapper 对象上的一组装饰器进行错误记录、重试连接等。但是,在处理完之后,我想让错误落入堆栈。一旦它到达顶部并且未处理,我希望它被吞下并执行我的 ApplicationResetter.Reset() 方法。

谁能告诉我怎么做?

如果这是不可能的,那么至少有一种方法可以解决这个问题,而不需要对每个可能收到此类错误的类引入对 ApplicationResetter 的依赖,并且不会实际关闭并重新启动我的应用程序(这看起来很难看)?

【问题讨论】:

【参考方案1】:

警告:对 3.5 还不熟悉,可能有更好的答案...

...但我的理解是,当事件到达未处理的异常处理程序时,应用程序可能会死掉——如果它没有死掉,它可能已经损坏到无论如何都应该死掉

如果您已经在处理 db-not-there 的情况并让其他异常通过,那么应用程序应该会死掉,因为它可能不稳定

【讨论】:

我正在通过重试和记录来处理这个案例,但是在完成之后,我的 DBWrapper.GetDataSet() 仍然必须向客户端返回某些内容或抛出错误。如果我抛出错误,除非我发现需要重置器依赖项,否则错误将冒泡。我希望尽可能高。 如果您在三个等待和重试周期之后未能找到数据库,则返回 null 并让调用者检查。否则,抛出一个自定义异常并让应用程序死掉 - 没有应用程序可以补偿不稳定/无法访问的数据库。 但这正是重点,我可以返回 null 或者我可以抛出错误,无论调用类必须采用 ApplicationResetter 依赖项 我想我对你的目的感到困惑。如果数据库消失了,而您希望 ApplicationResetter 启动并重新启动应用程序(或类似的东西),为什么不直接让 DBWrapper.GetDataSet 来做呢?【参考方案2】:

也许Application.ThreadException 事件会满足您的需求:

static void Main()

    Application.ThreadException += Application_ThreadException;
    //...
 

 static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
 
     // call ApplicationResetter.Reset() here
 

【讨论】:

我不确定这是否可行,我的应用程序不会终止吗? 我的错误,我在想 AppDomain.CurrentDomain.UnhandledException【参考方案3】:

System.Windows.Forms.Application.ThreadException 事件和System.AppDomain.CurrentDomain.UnhandledException 事件。

正如 Steven 所说,这些会使您的应用程序处于未知状态。除了将可能引发异常的调用放在 try/catch 块中之外,实际上没有其他方法可以做到这一点。

【讨论】:

【参考方案4】:

对于 Windows 窗体线程(调用 Application.Run()),在 Main() 的开头分配一个 ThreadException 处理程序。另外,我发现有必要调用 SetUnhandledExceptionMode:

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.Automatic);
Application.ThreadException += ShowUnhandledException;
Application.Run(...);

这是一个示例处理程序。我知道这不是您要查找的内容,但它显示了处理程序的格式。请注意,如果您希望异常是致命的,则必须显式调用 Application.Exit()。

static void ShowUnhandledException(object sender, ThreadExceptionEventArgs t)

    Exception ex = t.Exception;
    try 
        // Build a message to show to the user
        bool first = true;
        string msg = string.Empty;
        for (int i = 0; i < 3 && ex != null; i++) 
            msg += string.Format("0 1:\n\n2\n\n3", 
                first ? "Unhandled " : "Inner exception ",
                ex.GetType().Name,
                ex.Message, 
                i < 2 ? ex.StackTrace : "");
            ex = ex.InnerException;
            first = false;
        
        msg += "\n\nAttempt to continue? (click No to exit now)";

        // Show the message
        if (MessageBox.Show(msg, "Unhandled exception", MessageBoxButtons.YesNo, MessageBoxIcon.Error) == DialogResult.No)
            Application.Exit();
     catch (Exception e2) 
        try 
            MessageBox.Show(e2.Message, "Fatal error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
         finally 
            Application.Exit();
        
    

【讨论】:

这是正确的,但我认为还有更多。 Application.ThreadException 仅处理 UI 线程中抛出的异常。还有另一个事件 AppDomain.CurrentDomain.UnhandledException 处理非 UI 线程未处理的异常。在此处链接到 MSDN 示例 msdn.microsoft.com/en-us/library/…【参考方案5】:

在最新的 MSDN 问题中对未处理的异常进行了相当深入的解释: September 2008

【讨论】:

以上是关于有没有办法在 WinForms .NET 3.5 应用程序中为未处理的异常定义操作?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 SQL Express 使在 WinForms .NET 3.5 中开发的软件具有可移植性

有没有办法用 .Net 3.5 在 WPF 中模拟 UseLayoutRounding

与 .NET 2.0/3.5 一起使用的最佳免费 ORM 工具 [关闭]

有没有办法使用 C# 3.5 获取设备地理位置?

谁知道.NET Framework 3.5 的分布? [关闭]

如何向 ASP.NET 3.5 图表控件添加图例?