在调用Invoke之后发生异常时,.NET会显示堆栈跟踪,就像调用Invoke时发生错误一样。
以下示例:.NET将在UpdateStuff中发出错误而不是UpdateStuff - > BadFunction
有没有办法捕获“真正的”异常并显示正确的堆栈跟踪?
Private Sub UpdateStuff()
If (Me.InvokeRequired) Then
Me.Invoke(New UpdateStuffDelegate(AddressOf UpdateStuff))
Return
End If
Badfunction()
End Sub
Private Sub BadFunction()
Dim o As Object
o.ToString()
End Sub
答案 0 :(得分:3)
检查异常的InnerException属性。
答案 1 :(得分:1)
尝试......赶上阻挡。
答案 2 :(得分:1)
如果查看异常本身的TargetSite,它将为您提供动态调用的函数的名称(或者它获取引发当前异常的方法):
名称“BadFunction”字符串
该异常包含您从调用中获得的实际异常:System.NullReferenceException {“对象引用未设置为对象的实例。”} System.Exception
这是我的堆栈跟踪: 位于C:\ Development \ Test \ WindowsApplication1 \ WindowsApplication1 \ Form1.vb中的WindowsApplication1.Form1.BadFunction():第35行 位于C:\ Development \ Test \ WindowsApplication1 \ WindowsApplication1 \ Form1.vb中的WindowsApplication1.Form1.UpdateStuff():第22行
答案 3 :(得分:1)
是的,这不完美。在调用Invoke()的线程中捕获并重新抛出异常。必然,它缺少UI线程中代码的堆栈帧,它们在重新抛出异常时已经解开。它不使用InnerException属性并不是很好。
一种解决方法是在调用的方法中捕获异常并将其存储在私有字段中。更好的方法是使用BeginInvoke而不是Invoke。这将直接在UI线程中引发异常。
答案 4 :(得分:0)
结帐https://connect.microsoft.com/VisualStudio/feedback/details/386582/control-invoke-exception-handling 详细描述了这个问题,并允许您对其进行投票,以便Visual Studio团队可以再次将其置于优先级列表中(此时标记为“Not not Fix”)。
答案 5 :(得分:0)
汉斯提到了两个选择。六年后,有三分之一我觉得很方便。只需将您的调用包装在可以在本地范围内保留异常的委托中,然后使用它:
Exception exceptionFromDelegate = null;
formForSynchronizing.Invoke(new Action(() =>
{
try
{
SomeMethod();
}
catch (Exception error)
{
exceptionFromDelegate = error;
}
}));
if (exceptionFromDelegate != null)
{
// with .net 4.5 you can do this:
ExceptionDispatchInfo.Capture(exceptionFromDelegate).Throw();
// otherwise maybe go straight to your error reporting system
ReportException(exceptionFromDelegate);
}