我有一个创建一些任务的方法,然后在返回之前用WaitAll等待它们。问题是,如果这些任务被取消,那么WaitAll会抛出一个包含大量AggregateException个TaskCanceledException的vexing exception。
这意味着WaitAll将在两种不同的情况下抛出异常:
后者恰好适用于{{3}}的定义:它是在完全非特殊情况下抛出的异常,所以我必须抓住它才能恢复正常的控制流程。幸运的是,它很容易捕获,对吧?只需添加catch (AggregateException)
和 - 哦等等,这是在发生致命错误时被抛出的相同类型。
我需要在返回之前等待任务完成运行(我需要知道他们不再使用他们的数据库连接,文件句柄或其他任何东西),所以我确实需要WaitAll或类似的东西。如果任何任务出现故障,我确实希望这些异常作为未处理的异常传播。我只是不想取消取消。
如何阻止WaitAll
为已取消的任务抛出异常?
答案 0 :(得分:28)
AggregateException
提供了可用于这些情况的Handle
方法。例如,如果你想忽略TaskCanceledException
,你可以这样做:
var all = new AggregateException(
new NullReferenceException(),
new TaskCanceledException(),
new TaskCanceledException(),
new InvalidOperationException(),
new TaskCanceledException());
try
{
throw all;
}
catch (AggregateException errors)
{
errors.Handle(e => e is TaskCanceledException);
}
如果所有异常都是TaskCanceledException
类型,则Handle
方法不会抛出任何异常;否则,将抛出仅包含未处理异常的新AggregateException
。
答案 1 :(得分:1)
基于João Angelo's suggestion,此处为任务类扩展
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MySharedLibrary.Extensions
{
public static class TaskExtensions
{
// This code is based João Angelo's stackoverflow suggestion https://stackoverflow.com/a/8681687/378115
// Use this when a CancellationTokenSource is used
public static void SafeWait(this Task TargetTask, CancellationTokenSource TargetTaskCancellationTokenSource)
{
if (TargetTaskCancellationTokenSource.IsCancellationRequested == false)
{
TargetTaskCancellationTokenSource.Cancel();
}
SafeWait(TargetTask);
}
// Use this when no CancellationTokenSource is used
public static void SafeWait(this Task TargetTask)
{
try
{
if (TargetTask.IsCanceled == false)
{
TargetTask.Wait();
}
}
catch (AggregateException errors)
{
errors.Handle(e => e is TaskCanceledException);
}
}
}
}