【问题标题】:How to catch an Exception that has been thrown in the ContinueWith part of a task?如何捕获已在任务的 ContinueWith 部分中引发的异常?
【发布时间】:2016-12-07 09:39:15
【问题描述】:

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()); 
}

如果我启用调试选项“仅启用我的代码”,则程序会停止并收到警告:“用户代码未处理异常”

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

那么我如何/在哪里可以处理这个异常?

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

【问题讨论】:

  • 鉴于DoSomethingAsync 在其名称中声称是Async,它应该已经返回一个Task,所以使用StartNew 实际上是错误的。您正在创建一个创建任务的任务,而不是直接调用 DoSomethingAsync 并让它创建 Task
  • @Servy 我不知道那个命名约定。我将函数调用更改为DoSomeCalculations,以表明该函数本身不是async

标签: c# exception-handling .net-4.0 task-parallel-library continuewith


【解决方案1】:

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

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

【讨论】:

  • 我将您的答案标记为正确,因为对于 .Net-4.0,try/catch 和额外的延续都解决了我的问题。
【解决方案2】:

如果您使用的是 .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

【讨论】:

  • 我非常喜欢您的示例,但如前所述,我正在使用 .Net-4.0。尽管这可能是升级 Visual Studio 2010 的一个很好的理由。
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 2015-03-09
    • 1970-01-01
    • 1970-01-01
    • 2022-10-02
    • 1970-01-01
    • 2012-03-14
    • 1970-01-01
    • 2018-12-14
    • 2013-08-17
    相关资源
    最近更新 更多