捕获块未捕获异常
Posted
技术标签:
【中文标题】捕获块未捕获异常【英文标题】:Catch block not catching exception 【发布时间】:2010-09-28 05:14:38 【问题描述】:我有一个在 Load 事件处理程序中抛出 ApplicationException 的子表单(故意用于测试目的)。父窗体将 ChildForm.Show() 方法包装在 Try...Catch ex As Exception 块中。 catch 块只是显示一条消息并关闭子窗体。在 Visual Studio 2008 (.net 3.5 sp1) 中调试时,所有工作都按预期工作。但是,当我在 Visual Studio 之外运行它时,Catch 块似乎被遗漏了,并且发生了未处理的异常。知道这是为什么吗?
谢谢。
示例代码:
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim f2 As Form2
f2 = New Form2
Try
MessageBox.Show("Opening form 2")
f2.ShowDialog()
Catch ex As Exception
f2.Close()
MessageBox.Show("Form 2 closed.")
End Try
End Sub
End Class
Public Class Form2
Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Throw New ApplicationException("Test Form_Load")
End Sub
Public Sub New()
' This call is required by the Windows Form Designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
End Sub
End Class
堆栈跟踪:
System.ApplicationException: 在 WindowsApplication1.Form2.Form2_Load 测试 Form_Load(Object sender, EventArgs e) 在 UnhandledExceptionTest2\WindowsApplication1\Form2.vb System.Windows.Forms.Form.OnLoad(EventArgs e) System.Windows.Forms.Form.OnCreateControl() System.Windows.Forms.Control.CreateControl(布尔 fIgnoreVisible) System.Windows.Forms.Control.CreateControl() System.Windows.Forms.Control.WmShowWindow(Message& m) 在 System.Windows.Forms.Control.WndProc(Message&> m) 在 System.Windows.Forms.ScrollableControl.WndProc(Message&> m) 在 System.Windows.Forms.ContainerControl.WndProc(Message&> m) 在 System.Windows.Forms.Form.WmShowWindow(Message&> m) 在 System.Windows.Forms.Form.WndProc(Message&> m) 在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message&> m) 在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message&> m) 在 System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd,Int32 msg,IntPtr wparam,IntPtr 参数)【问题讨论】:
是的——描述的很模糊...... 【参考方案1】:Form.Load 事件的行为方式与 Windows 窗体中的大多数其他事件相同。它由消息循环调度,在这种情况下,当 Windows 发送 WM_SHOWWINDOW 消息时。消息循环中有一个异常处理程序,可防止未捕获的异常终止消息循环。该异常处理程序引发 Application.ThreadEvent 事件。默认事件处理程序显示未处理的异常对话框。
长话短说,您无法在按钮 Click 处理程序中捕获 Load 事件中引发的异常。除了在 Load 事件处理程序本身中捕获和处理异常之外,很难做到正确,我建议您向表单添加一个公共方法。像 Initialize() 这样的东西。将代码从 Load 事件移到该方法中。调用 Show() 方法后调用 Initialize(),现在可以捕获异常了。
【讨论】:
+1 谢谢!太糟糕了,只有一个糟糕的解决方法...更多代码 = 更多错误 ;-) 我多年来一直在编写“WinForms”,这是我第一次遇到这个问题。【参考方案2】:我也有同样的问题。我最终所做的是捕获所有异常。在 C# 中:
Application.ThreadException += new ThreadExceptionEventHandler(MyHandler);
然后显示表格。
我很想知道是否有人有更好的解决方案。
【讨论】:
【参考方案3】:我为 C# 道歉(我不知道 Vb 语法)
你在做这样的事情吗:
ChildForm child = new ChildForm();
try
child.Show();
catch(Exception ex)
.....
如果是这样,我相信 Load 事件会发生在 New 上,而不是 Show(); (节目会触发激活)
【讨论】:
当我在调试器中单步执行时,Load 事件发生在 Show() 上。【参考方案4】:新窗口有自己的线程,它自己加载。要验证这一点,您可以尝试在异常之前将 Thread.Sleep
放入 Form2_Load 几秒钟。在您遇到异常之前,您的主线程窗口应该继续执行。
【讨论】:
可以理解,为什么代码在 Visual Studio 中的工作方式与在 VS 之外运行时不同? 嗯...我错过了它调用的是 ShowDialog 而不是 Show,所以它应该阻塞。那就更令人费解了:-( 当我在 VS 之外运行程序时,使用 Attach to Process... 工具并打开 Threads and Call Stack 窗口,我观察到 Form2_Load 事件正在主线程上运行,并且调用堆栈显示 Form1_ButtonClick 调用 Form2_Load。然而,这种行为仍然存在。 查看 nobugz 和 mgilman 的 cmets,因为他们似乎在正确的轨道上。以上是关于捕获块未捕获异常的主要内容,如果未能解决你的问题,请参考以下文章