WinForm“全局”MDI子窗体“唯一”捕获异常

问题描述:

我有一个MDI父/子应用程序。
在Program.cs文件中,我针对ThreadException和UnhandledException都有一个全局异常处理程序。WinForm“全局”MDI子窗体“唯一”捕获异常

那些工作正常。

当我在全局级别得到未处理的异常时,在UnhandledException处理程序内部调用Environment.Exit(1)来关闭应用程序,因为我不知道应用程序的当前状态。

在子窗体中,我“通常”将以下内容添加到事件处理程序中。

try 
{ 
    // Some Code 
} 
catch (Exception ex) 
{ 
    HandleException(ex); 
    MessageBox.Show("Some message"); 
    this.Close(); 
} 

我想知道是否有将我所有的孩子形成了全球性的异常处理程序(我有他们继承碱基形式),可以捕获异常,并关闭子窗体不关闭的方式整个应用程序。
这样,如果开发人员“忘记”在事件上添加try catch块,它不会轰炸整个应用程序。

+0

我同意崩溃转储会很方便。我有一个全局的异常记录器,可以保存堆栈跟踪,一些性能设置等等,它们保存在一个sql数据库*审阅,但我不想因为有人忘记添加try catch而终止应用程序像在数字文本框中输入字符串一样简单。 – goroth

我同意这通常是一个糟糕的主意,但是如果您的全局异常处理程序具有“发件人”对象,则可以尝试使用sender.GetType()来获取该对象的类型。您可以通过说if (sender.GetType().IsSubclassOf(typeof (BaseClass))) { // then do something }来查看它是否继承了您的基本形式。

如果发件人是子窗体的子控件(而不是窗体本身),那么您可能需要使用辅助方法遍历几个级别的祖先来查找父窗体(例如:发件人可能是一个文本框,sender.Parent可能是一个面板,sender.Parent.Parent可能是表单)。您可以递归检查父项,直到父项为空,或者父项来自基类。

您也可以循环遍历MdiParent窗体的MdiChildren,以查看它们中是否有任何窗体导致异常。那么你不需要从基类继承。

此外,在ThreadException的情况下,如果你有在一些匿名方法发射后不管型线,这将有可能无法正常工作......

我只在一个项目中使用全局异常处理,并且我似乎记得它在调试模式下无法正常工作,因为您获得了Visual Studio异常帮助程序,所以我没有快速测试此方法 - 只是将其视为一般“”伪代码“建议。

+0

当然,如果你启动一个线程并且你不希望它再次与你的表单交互,那么理论上你可以吞下异常,表单将继续运行(再次 - 为无效状态,数据创建巨大潜力腐败等,但你可以做到)。如果您的表单正在等待线程完成执行,那么您必须捕获该级别的错误(通过有意义的超时并意识到预期的操作从未完成)。 –

+0

您可以使用System以编程方式访问堆栈跟踪。诊断。 'string fileName = new StackTrace()。GetFrame(1).GetFileName();'会为您提供第1帧的文件名 - 您可以遍历帧,还有其他方法,如GetFileName()获取方法名,类型等。 –

+0

在你的帮助下,我非常接近。我结束了对“新的StackTrace(exception,true).GetFrames()”,然后使用“bool cancelExit = stackFrame.GetMethod()。reflectedType.IsSubclassOf(typeof(Project.BaseForm));”;但后来我发现,因为我没有/无法得到崩溃的窗体的实例,所以我无法关闭/处理那个破损的窗体......如果我只能弄清楚如何获取窗体的窗体ID窗体,我可以发送一个Windows消息来关闭该窗体。仍在挖掘。 – goroth

正如我在评论中已经说过的,我不太喜欢你的方法,特别是你正在捕捉最一般的异常的情况。

该消息只能部分帮助您解决问题。崩溃可以帮助你完全解决问题,包括调用堆栈,堆上的对象,CPU寄存器等。只要学习How to take a crash dump并分析它。通过关闭MDI窗体,您忽视的事实是你的应用程序的数据可能会处于无效状态

而行,这就是编码风格,也许不应该在这里讨论。

你可以做什么叫做Aspect Oriented Programming (APO) [Wikipedia]。方面是适用于你的代码的几个部分,你不想明确地在任何地方实现它。

您将一个方面实现为代码,然后在配置文件中定义要应用该代码的位置,例如,通过命名约定。

魔法发生在编译时。编译普通代码后,中间代码编织器(IL-weaver)修改IL代码并在任何地方插入方面。

您需要一个库,如PostSharp(商业)或AfterThought(免费)。 PostSharp甚至有examples for exception handling,可以很容易地用于显示消息框。

当你第一次尝试它的时候,它需要一些思维弯曲,所以一定要遵循一些教程,然后再将这个conceopt应用到你的代码中。

+0

我同意你关闭MDI子代并在发生未处理的异常时运行应用程序是不好的做法,但在此应用程序中,所有MDI表单都是相互独立的,并且内部没有全局/静态方法/属性/变量应用程序。所以在这个应用程序中,杀死一个表单而不杀死整个应用程序是安全的。但我确实喜欢你发送的链接/信息,并且会阅读它们中的每一个以供将来使用。 – goroth