【问题标题】:Exception continuation doesn't work with completion continuation异常延续不适用于完成延续
【发布时间】:2012-10-14 10:51:25
【问题描述】:

我有这个简单的 TPL 代码:

var t = Task.Factory.StartNew(() => { throw null; })
    .ContinueWith((ant) => { Console.WriteLine("Success"); }, 
        TaskContinuationOptions.OnlyOnRanToCompletion)
    .ContinueWith((ant) => { Console.WriteLine("Error"); }, 
        TaskContinuationOptions.OnlyOnFaulted);
t.Wait();

我得到一个未处理的异常:

Unhandled Exception: System.AggregateException: One or more errors occurred.
...

如果我将t.Wait() 放在try-catch 中,异常就会被捕获,我知道它违背了使用异常延续的全部意义。现在,如果我删除完成延续,任务引发的异常将在异常延续中处理,我没有得到上述异常。有人可以对正在发生的事情有所了解吗? 我正在使用 .NET 4.0 的 VS2010 SP1

【问题讨论】:

  • 您计划依次执行 3 个任务。第一个“throw null”任务以AggregateException 结束,因此第二个“Success”任务根本没有开始。更不用说第三个“错误”了。
  • @JiajiWu,我已经计划了两个任务按顺序执行 - 只有一个延续应该在父任务完成后运行。很明显,完成延续不会因为抛出异常而运行。但我不明白你为什么说异常继续没有运行?
  • a.ContinueWith(b, TaskContinuationOptions.OnlyOnRanToCompletion).ContinueWith(c, TaskContinuationOptions.OnlyOnFaulted) 表示“执行a;如果a成功完成,执行b;如果b失败,执行c。”。听起来您打算做的是“执行a;如果a成功完成,则执行b;否则(如果a失败),则执行c。”。那么你应该选择 svick 的解决方案。

标签: .net exception-handling task-parallel-library continuations


【解决方案1】:

ContinueWith() 不返回原始的Task,它返回一个Task 表示继续。在您的情况下,继续被取消,因为原始 Task 没有运行完成。因为第二个Task 没有出错,所以你的第三个Task 也被取消了,这就是为什么你将TaskCanceledException 包裹在AggregateException 中。

你可以做的是有一个延续,它同时做这两个动作。比如:

var t = Task.Factory.StartNew(() => { throw null; })
    .ContinueWith(
        ant =>
        {
            if (ant.IsFaulted)
                Console.WriteLine("Error");
            else
                Console.WriteLine("Success");
        });

如果你经常这样做,你可以为此创建一个扩展方法(加上Task<T> 的通用版本,Action<T>onSuccess):

public static Task ContinueWith(
    this Task task, Action onSuccess, Action<AggregateException> onError)
{
    return task.ContinueWith(
        ant =>
        {
            if (ant.IsFaulted)
                onError(task.Exception);
            else
                onSuccess();
        });
}

用法:

var t = Task.Factory.StartNew(() => { throw null; })
    .ContinueWith(
        () => { Console.WriteLine("Success"); },
        ex => { Console.WriteLine("Error"); });
t.Wait();

此外,这假设您知道您原来的Task 不会被取消。如果不是这种情况,那就是您需要处理的另一种情况。

【讨论】:

    猜你喜欢
    • 2013-04-22
    • 1970-01-01
    • 2021-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-20
    • 2011-10-30
    • 1970-01-01
    相关资源
    最近更新 更多