处理Tpl中的异常

时间:2012-03-30 19:42:02

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

我已经阅读了很多关于如何处理TPL中的异常但却不太了解的内容。

让我们看看这个示例代码:

var task1 = new Task(() => { throw new Exception("Throw 1"); });
var task2 = task1.ContinueWith(t => Console.WriteLine("Catch 1:{0}", t.Exception.Message), 
                              TaskContinuationOptions.OnlyOnFaulted);
var task3 = task2.ContinueWith(t => Console.WriteLine("Continuation"));

task1.Start();
try {
    task1.Wait();
}
catch (Exception ex) {
    Console.WriteLine("Wait Exception: {0}", ex.Message);
}

我希望打印

Catch 1
Continuation

但是我得到了

Catch 1
Continuation
Wait Exception

这意味着当任务完成并且任务终结器最终将拆除应用程序时,异常仍被视为未处理。

如何在延续中处理异常,以便终结器不会抛出?同时我希望任务保持在故障状态,因此将任务包装在try / catch中不会工作


背景是我想实现指定here的异步事件模式,但有错误处理。我的完整代码看起来像这样

public IAsyncResult Begin(AsyncCallback callback, object state, Action action) {
    var task1 = new Task(action);
    var task2 = task1.ContinueWith(t => HandleException(t.Exception), 
                                   TaskContinuationOptions.OnlyOnFaulted);
    if (callback != null) {
        var task3 = task2.ContinueWith(t => callback(t),
                                      TaskScheduler.FromCurrentSynchronizationContext());
        var task4 = task3.ContinueWith(t => HandleException(t.Exception), 
                                       TaskContinuationOptions.OnlyOnFaulted);
    }

    task1.Start();

    return task;
}

1 个答案:

答案 0 :(得分:3)

你等待失败的任务,如果你仔细阅读documentation on Task.Wait,你会发现在这种情况下等待将重新抛出异常。

但是,如果你等待task3,一切都应该按预期工作。

当然你应该牢记这一点:

  

当您使用OnlyOnFaulted选项时,保证了   前提中的异常属性不为null。你可以用它   捕获异常的属性,看看引起了哪个异常   任务到错。如果您不访问Exception属性,则   异常将无法处理。此外,如果您尝试访问结果   已被取消或出现故障的任务的属性,一个新的   异常将被提出。

(参考here

最后又是How to handle exceptions thrown by tasks

的另一个好消息来源

我希望这会有所帮助。