如何实现保留异常顺序的自定义Task.WhenAll方法?
实现按位置顺序传播异常的Task.WhenAll替代方法
.NET 8中,非泛型的Task.WhenAll行为发生了变更——现在它会按异常发生的时间顺序抛出,而非原有的任务数组位置顺序。如果你的测试依赖旧版按位置排序异常的行为,可以实现以下替代方法:
方法签名
/// <summary> /// 创建一个在所有提供的任务完成后才完成的任务。 /// 该任务会按任务数组中的位置顺序(而非时间顺序)包含故障任务的异常。 /// </summary> public static Task WhenAll_OrderedExceptions(params Task[] tasks)
预期行为示例
测试代码:
async Task DoAsync(string title, int delay) { await Task.Delay(delay); throw new Exception(title); } Task t1 = DoAsync("A", 200); Task t2 = DoAsync("B", 100); try { WhenAll_OrderedExceptions(t1, t2).Wait(); } catch (AggregateException aex) { Console.Write($"Error message: {aex.Message}"); }
预期输出:
Error message: One or more errors occurred. (A) (B)
(注:.NET 8原生Task.WhenAll会输出Error message: One or more errors occurred. (B) (A),不符合需求)
实现代码
public static async Task WhenAll_OrderedExceptions(params Task[] tasks) { // 等待所有任务完成,无论成功或失败 await Task.WhenAll(tasks).ConfigureAwait(false); // 按任务数组的原始顺序收集所有异常 var exceptions = new List<Exception>(); foreach (var task in tasks) { if (task.IsFaulted) { exceptions.AddRange(task.Exception.InnerExceptions); } } // 存在异常时,抛出按位置排序的AggregateException if (exceptions.Count > 0) { throw new AggregateException(exceptions); } }
实现说明
- 先调用原生
Task.WhenAll等待所有任务完成,确保能获取到所有任务的执行状态。 - 遍历任务数组,严格按原始位置顺序收集每个故障任务的内部异常。
- 若收集到异常,抛出包含有序异常的
AggregateException;无异常则方法正常完成。
该实现完全匹配旧版Task.WhenAll的异常排序逻辑,能满足依赖旧行为的测试需求。
内容的提问来源于stack exchange,提问作者Theodor Zoulias
相关产品推荐
相关产品推荐

