如何捕获在任务的 ContinueWith 部分抛出的异常?

How to catch an Exception that has been thrown in the ContinueWith part of a task?

button_click 事件中,我启动了 Task 以异步执行一些耗时的计算。我使用 Task.ContinueWith 并将继续的 TaskSheduler 设置为 UI 同步上下文,以在 Textbox.

中显示异步计算的结果

现在假设最后一部分抛出这样的异常:

private void button1_Click(object sender, EventArgs e)
{
   Task.Factory.StartNew(DoSomeCalculations).ContinueWith
      (t => { throw new Exception("Some Exception"); }, TaskScheduler.FromCurrentSynchronizationContext()); 
}

如果我启用调试选项 "Enable Just My Code" 然后程序停止并且我收到警告:"Exception was unhandled by user code"

但是如果我不设置这个选项,异常就会消失在任何地方(没有程序崩溃,什么都没有)。

所以how/where我可以处理这个异常吗?

编辑: 请注意,如标签所示,我使用的是 .NET-4.0

如果你想处理异常,那么要么在延续本身中有一个 try/catch 块,以便它处理自己的异常,要么向延续添加一个额外的延续来处理异常。

请注意,如果您使用 await 而不是 ContinueWith 添加延续,通常会更简单,尤其是在处理异常时,因为它会代表您添加延续。

如果您使用的是 .NET Framework 4.5,则有一种处理 Task 对象的新方法。

private async void button1_Click(object sender, EventArgs e)
{
   await Task.Run(() =>
   {
       DoSomethingAsync()
   });
   //this line will run in UI thread
   throw new Exception("Some Exception");
}

请注意,当您使用 async 关键字时,Task 对象内发生的任何异常都会被编译器创建的状态机吞没。但是这个异常是在 Task 对象中设置的,所以基本上你仍然可以使用 Task 对象引用这个异常。

供您参考: http://blog.stephencleary.com/2012/02/async-and-await.html

根据最佳实践,如果我们无法避免使用 async void 方法(尤其是对于事件处理程序),则应在该方法中实现 try catch。但是您需要确保您调用的所有异步方法都具有异步任务方法签名,以便捕获抛出的异常。