有没有办法在 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 工具 [关闭]