class AggregatedExceptions
{
static void Main()//从任务失败重新包装多个异常
{
MainAsync().Wait();
}
private async static Task MainAsync()
{
Task task1 = Task.Run(() => { throw new Exception("Message 1"); });
//Id = 2, Status = System.Threading.Tasks.TaskStatus.Faulted, Method = "{null}", Result = "{尚未计算}"
Task task2 = Task.Run(() => { throw new Exception("Message 2"); });
//$exception {"Message 2"} System.Exception 执行这句有异常
//Id = 3, Status = System.Threading.Tasks.TaskStatus.WaitingForActivation, Method = "{null}", Result = "{尚未计算}"
try
{
await Task.WhenAll(task1, task2);
}
catch (Exception e)
//$exception {"Message 1"} System.Exception
{
Console.WriteLine("Caught {0}", e.Message);
}
try
{
await Task.WhenAll(task1, task2).WithAggregatedExceptions();
}
catch (AggregateException e)
{
Console.WriteLine("Caught {0} exceptions: {1}", e.InnerExceptions.Count,
string.Join(", ", e.InnerExceptions.Select(x => x.Message)));
//x {"Message 1"}
}
}
}
public static AggregatedExceptionAwaitable WithAggregatedExceptions(this Task task)
{
if (task == null)
{
throw new ArgumentNullException("task");
}
return new AggregatedExceptionAwaitable(task);
}
public struct AggregatedExceptionAwaitable
{
private readonly Task task;
internal AggregatedExceptionAwaitable(Task task)
//task Id = 6, Status = System.Threading.Tasks.TaskStatus.Faulted, Method = "{null}", Result = "{尚未计算}"
{
this.task = task;
}
public AggregatedExceptionAwaiter GetAwaiter()
{
return new AggregatedExceptionAwaiter(task);
}
}
public struct AggregatedExceptionAwaiter : ICriticalNotifyCompletion
{
private readonly Task task;
internal AggregatedExceptionAwaiter(Task task)
{
this.task = task;
}
// Delegate most members to the task's awaiter
public bool IsCompleted { get { return task.GetAwaiter().IsCompleted; } }
public void UnsafeOnCompleted(Action continuation)
{
task.GetAwaiter().UnsafeOnCompleted(continuation);
}
public void OnCompleted(Action continuation)
{
task.GetAwaiter().OnCompleted(continuation);
}
public void GetResult()
{
// This will throw AggregateException directly on failure,
// unlike task.GetAwaiter().GetResult()
task.Wait();
}
}
编写一个Task<T>的扩展方法,从而创建一个可从任务中抛出原始AggregateException
的特殊可等待模式成员。
Task<T>也需要一个类似的方法,即在GetResult()中使用return task.Result,而不是
调用Wait()。我们想自己不想处理的部分委托给了任务的awaiter,而回避了GetResult()
常规行为,即对异常进行拆包。在调用GetResult时,我们知道任务处于即将结束的状态,
因此Wait()调用可立即返回。
WithAggregatedExceptions()返回自定义的可等待模式成员,而后者的GetAWaiter()
又提供自定义的awaiter,并支持C#编译器所需要的操作来等待结果。
输出
Caught Message 1
Caught 2 exceptions: Message 1, Message 2