这是我的假设例子。我有一个非常简单的WPF窗口,带有一个Button。 Button.Click事件有一个像这样的处理程序。
Action doit = () =>
{
Action error = () => { throw new InvalidOperationException("test"); };
try {
this.Dispatcher.Invoke(error, DispatcherPriority.Normal);
} catch (Exception ex) {
System.Diagnostics.Trace.WriteLine(ex);
throw;
}
};
doit.BeginInvoke(null, null);
我希望通过Trace.WriteLine
调用捕获并记下该异常。相反,没有捕获异常并且应用程序中断。
有人知道可能的解释吗?为了捕获由Dispatcher.Invoke
调用的委托引发的异常,您建议使用哪种解决方法?
更新1 :我在异常处理代码中添加了throw
。我不想实际忽略该异常。我的问题的重点是正确处理它。问题是永远不会执行异常处理代码。
请记住,这是一个假设的例子。我的真实代码看起来不像那样。另外,假设我无法更改要调用的方法中的代码。
更新2 :考虑这个类似的例子。我有一个Windows窗体窗口而不是WPF窗口。它有一个按钮,几乎完全相同的处理程序。唯一的区别在于调用代码。它是这样的。
this.Invoke(error);
在Windows窗体中,执行异常处理代码。为什么不同?
答案 0 :(得分:6)
更新:要观察其他线程中的异常,您需要使用Task
,将其排入Dispatcher
线程(使用TaskScheduler.FromCurrentSynchronizationContext
) ,等等,就这样:
var ui = TaskScheduler.FromCurrentSynchronizationContext();
Action doit = () =>
{
var error = Task.Factory.StartNew(
() => { throw new InvalidOperationException("test"); },
CancellationToken.None,
TaskCreationOptions.None,
ui);
try {
error.Wait();
} catch (Exception ex) {
System.Diagnostics.Trace.WriteLine(ex);
}
};
doit.BeginInvoke(null, null);
更新(再次):由于您的目标是可重复使用的组件,我建议您转移到基于Task
的界面或其他基于SynchronizationContext
的界面,例如event-based asynchronous pattern,而不是将组件基于Dispatcher
或ISynchronizeInvoke
。
Dispatcher
- 基于组件仅适用于WPF / Silverlight;基于ISynchronizeInvoke
的组件仅适用于Windows窗体。基于SynchronizationContext
的组件将透明地与WPF或Windows Forms一起使用,并且(通过更多工作)ASP.NET,控制台应用程序,Windows服务等。
基于事件的异步模式是编写基于SynchronizationContext
的组件的旧推荐方法;它仍然适用于.NET 3.5时代代码。但是,如果您使用的是.NET 4,则任务并行库更加灵活,干净且功能强大。 TaskScheduler.FromCurrentSynchronizationContext
下方使用SynchronizationContext
,是编写需要此类同步的可重用组件的新方法。