处理Tpl中的异常

本文关键字:异常 Tpl 处理 | 更新日期: 2023-09-27 18:29:44

我读了很多关于如何在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中包装任务将不起作用。


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

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

处理Tpl中的异常

您对失败的任务进行等待,如果您阅读了task的文档。仔细等待,您会发现在这种情况下,等待会重新引发异常。

但是,如果您等待task3,一切都应该按预期进行。

当然你应该记住这一点:

当您使用OnlyOnFaulted选项时,可以保证先行词中的异常属性不为null。你可以用它属性捕获异常并查看是哪个异常导致任务出错。如果未访问Exception属性,则异常将无法处理。此外,如果您尝试访问Result已取消或出现故障的任务的属性将引发异常。

(此处参考)

最后是关于如何处理任务引发的异常的另一个好消息来源

我希望这能有所帮助。