等待一个任务,并使用OnlyOnFaulted延续会导致AggregateException异常

41

我有一些简单的代码需要重现:

var taskTest = Task.Factory.StartNew(() =>
{
    System.Threading.Thread.Sleep(5000);

}).ContinueWith((Task t) =>
{
    Console.WriteLine("ERR");
}, TaskContinuationOptions.OnlyOnFaulted);

try
{
    Task.WaitAll(taskTest);
}
catch (AggregateException ex)
{
    foreach (var e in ex.InnerExceptions)
        Console.WriteLine(e.Message + Environment.NewLine + e.StackTrace);
}

然而,在try catch块中抛出了意外的TaskCanceledException(它位于AggregateException InnerExceptions对象中)。"任务已取消"。
为什么会出现这个异常?任务的继续没有触发,也没有生成任何异常,但是在等待时仍然会收到聚合异常....
我希望有人可以解释这对我有什么意义 :)

我和你的情况完全一样。我认为更加优雅和直观的做法是仅传递上一个任务的结果。抛出TaskCanceledException让人感到相当惊讶... - NickL
1个回答

56
你不是在等待一个带有OnlyOnFaulted继续操作的任务,而是在等待该继续操作(由ContinueWith返回)。由于原始任务正常返回,因此该继续操作永远不会触发,因此它的行为就像被取消一样。
我理解了。
我猜你想创建任务,添加继续操作,但是然后等待原始任务:
var taskTest = Task.Factory.StartNew(() =>
{
    System.Threading.Thread.Sleep(5000);

});
taskTest.ContinueWith((Task t) =>
{
    Console.WriteLine("ERR");
}, TaskContinuationOptions.OnlyOnFaulted);

1
很好的解释,只有一个评论,在这种情况下最好不要使用Factory.StartNew()方法,因为任务可能会在定义继续之前开始。在这里我会使用new Task()构造函数,然后设置ContinueWith(),最后调用Start()方法。这有意义吗? - Jorge Fioranelli
1
@JorgeFioranelli:任务在继续定义之前启动会有什么问题吗?我相信TPL可以毫无问题地处理这个。 - Jon Skeet
2
不确定,但我相信在继续添加之前任务可能会抛出异常,然后处理程序将不会被调用。我是对的吗? - Jorge Fioranelli
7
如果续接被附加到已完成的任务上,并且该任务以异常结束,那么续接将立即执行。(如果任务未发生故障,则会取消。) - Olly
@Timo:老实说,我建议你提出一个新问题来问。请记住,在这个问题被提出和回答的时候,async/await甚至还不存在。 - Jon Skeet
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接