.net 是否可以在委托驱动的“代理”后面处理异常;控制。调用";呼叫

.net 是否可以在委托驱动的“代理”后面处理异常;控制。调用";呼叫,.net,vb.net,exception-handling,.net-3.5,invoke,.net,Vb.net,Exception Handling,.net 3.5,Invoke,我有一个在套接字处理线程中运行的事件处理程序,它使用Invoke更新UI状态 我有一个失控的FormatException,在调用堆栈的更上层,我试图捕捉它来分析它,但我发现我无法让调试器在UI线程中中断-无论我做什么,异常似乎都会冒泡到调用线程 Private Delegate Sub newDataDelegate(ByVal data As String) Private Sub onNewData(ByVal data As String) Handles _server.clientH

我有一个在套接字处理线程中运行的事件处理程序,它使用
Invoke
更新UI状态

我有一个失控的
FormatException
,在调用堆栈的更上层,我试图捕捉它来分析它,但我发现我无法让调试器在UI线程中中断-无论我做什么,异常似乎都会冒泡到调用线程

Private Delegate Sub newDataDelegate(ByVal data As String)
Private Sub onNewData(ByVal data As String) Handles _server.clientHasData
   If Me.InvokeRequired Then
      Me.Invoke(New newDataDelegate(AddressOf onNewData), data)
      Exit Sub
   End If

   Try
      updateGuiWith(data)
   Catch ex As FormatException
      System.Diagnostics.Debugger.Break()
   End Try
End Sub
堆栈跟踪:

位于System.Windows.Forms.Control.MarshaledInvoke(控件调用方、委托方法、对象[]参数、布尔同步)
位于System.Windows.Forms.Control.Invoke(委托方法,对象[]args)
at.MainForm.onNewData(字符串数据)
in.vb:第377行
at.Server.onProbeData(字符串数据)
输入:第104行
=修订)

结果是调试器将调用堆栈分解到较低的位置(在套接字线程中调用
onNewData
的代码中),堆栈跟踪在调用站点结束。我无法找出导致异常的原因。(更糟糕的是,调用在大多数情况下对同一个参数有效,因此,如果没有调试器的帮助,我无法预测和查找该参数。)

在我进一步提取一个独立的测试用例之前,委托驱动调用之后是否会出现异常的预期行为

我要说是的,这是为了使异常冒泡。如果我正确理解了本文,异常将被吞没,异常信息将返回到Invoke函数,并在那里重新抛出。但是,如果使用
BeginInvoke
执行异步调用,则不会通过
BeginInvoke
调用引发异常

我没有使用VS Express,但通常在“调试”>“异常”下,选中“公共语言运行时异常”旁边的“抛出”框。然后,调试器应该在发生第一个异常的地方停止

虽然情况可能并非如此,但您可以检查代码中的属性,例如可能导致调试器跳过引发异常的代码的属性

委托驱动调用后引发的异常是否会出现这种预期行为

不,这是因为您实际上没有使用委托的Begin/Invoke()方法。您使用的是Control.Invoke(),这是一个控件类的方法,它仅将委托作为参数。它的行为与委托的Begin/Invoke方法非常不同,命名选择有点不幸。主要区别是:

  • 调用BeginInvoke时不需要调用EndInvoke
  • 调用会将异常封送回,而BeginInvoke调用不会
  • 现在让您感到痛苦的是,为调用而封送回来的异常是最内部的异常。您只能看到引发灾难的异常。如果它被另一个异常捕获并重新引发,并且在其InnerException成员中传递了原始异常,那么您根本看不到这些异常
是的,这会使您在查看堆栈跟踪时很难弄清楚从点A到点B是如何得到的。非常不幸的行为,设计选择并不明显。除了在调用的代码中捕获和处理异常之外,没有简单的解决方法


或者,为了支持BeginInvoke,通常使用您希望使用的方法,因为您不希望您的线程因UI更新延迟而陷入困境。异常将在具有完整堆栈跟踪诊断的UI线程上引发。

Catch-ex-As-FormatException
替换为
Catch-ex-As-exception
为我提供了我正在寻找的调用的线程中断,而实际的异常结果是
InvalidCastException
。内部异常是
FormatException
,这就是它没有被捕获的原因

<>我对.NET中异常的理解仍然是相当简单的(作为C++开发人员的首要),所以这种不同级别的异常包装器的概念是相当陌生的。但最终,这一机制正如汉斯在回答中所解释的那样

从长远来看,切换到
BeginInvoke
将完全避免这种头痛。不过,现在我有了堆栈跟踪,可以解决实际问题


问题的答案是,异常可以在委托驱动的“Control.Invoke”调用后面处理吗?是

注意:这是VisualBasic2008Express版,它使用.NET3.5。或者至少我在尝试?!我会考虑切换到
BeginInvoke
(我不需要
EndInvoke
?这是否意味着我现在应该使用它呢?),但我仍然很好奇这里发生了什么。目前,我正在研究报告的异常类型在某种程度上不正确的理论,并等待问题再次出现,使用更通用的
Catch ex As exception
来证明这一点。正如我所解释的,您将只捕获最内部的异常。请注意,在跨线程捕获和处理异常方面的智慧是有限的。如果invoke方法不是为正确恢复程序状态而编写的,则无法正确恢复程序状态。明白了吗。最后一件事-你能证实或否认我对
EndInvoke
(从我的第一条评论中)的怀疑吗?这是我的回答,第一个要点。我想我的后续问题是“我现在是否应该用
Invoke
EndInvoke
?”,因为当你说
BeginInvoke
不需要它时,你似乎在说
BeginInvoke
Invoke
之间有区别,选中“公共语言运行时异常”旁边的“抛出”框
,对于使用和处理大量异常的应用程序来说,这是不可行的总的来说,唉。
at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
at <X>.MainForm.onNewData(String data)
   in <X>.vb:line 377
at <X>.Server.onProbeData(String data)
   in <X>:line 104