代码之家  ›  专栏  ›  技术社区  ›  Orion Edwards

有可能从一个任务中获得成功的结果吗?当其中一个任务失败时?

  •  1
  • Orion Edwards  · 技术社区  · 5 年前

    鉴于以下情况:

    var tPass1 = Task.FromResult(1);
    var tFail1 = Task.FromException<int>(new ArgumentException("fail1"));
    var tFail2 = Task.FromException<int>(new ArgumentException("fail2"));
    
    var task = Task.WhenAll(tPass1, tFail1, tFail2);
    task.Wait();
    

    对task.Wait()的调用抛出 AggregateException ,其内部异常包含 fail1 fail2 tPass1 成功的结果?

    这可能吗?

    WhenAll 已经完成,通过 tPass1.Result 惠纳尔 ?

    0 回复  |  直到 4 年前
        1
  •  5
  •   Theodor Zoulias    4 年前

    Result 属性,因为它抛出。所以要有一个部分成功的结果 WhenAll 惠纳尔 它从不抛出,而是返回结果和异常 ValueTuple 结构。

    public static Task<(T[] Results, Exception[] Exceptions)> WhenAllEx<T>(
        params Task<T>[] tasks)
    {
        tasks = tasks.ToArray(); // Defensive copy
        return Task.WhenAll(tasks).ContinueWith(t => // return a continuation of WhenAll
        {
            var results = tasks
                .Where(t => t.Status == TaskStatus.RanToCompletion)
                .Select(t => t.Result)
                .ToArray();
            var aggregateExceptions = tasks
                .Where(t => t.IsFaulted)
                .Select(t => t.Exception) // The Exception is of type AggregateException
                .ToArray();
            var exceptions = new AggregateException(aggregateExceptions).Flatten()
                .InnerExceptions.ToArray(); // Flatten the hierarchy of AggregateExceptions
            if (exceptions.Length == 0 && t.IsCanceled)
            {
                // No exceptions and at least one task was canceled
                exceptions = new[] { new TaskCanceledException(t) };
            }
            return (results, exceptions);
        }, default, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
    }
    

    var tPass1 = Task.FromResult(1);
    var tFail1 = Task.FromException<int>(new ArgumentException("fail1"));
    var tFail2 = Task.FromException<int>(new ArgumentException("fail2"));
    
    var task = WhenAllEx(tPass1, tFail1, tFail2);
    task.Wait();
    Console.WriteLine($"Status: {task.Status}");
    Console.WriteLine($"Results: {String.Join(", ", task.Result.Results)}");
    Console.WriteLine($"Exceptions: {String.Join(", ", task.Result.Exceptions.Select(ex => ex.Message))}");
    

    输出:

    状态:RANTO完成
    结果:1
    异常:故障1,故障2

        2
  •  8
  •   Fabio    5 年前

    也许 吧

    public async Task<Task[]> RejectFailedFrom(params Task[] tasks)
    {
        try
        {
            await Task.WhenAll(tasks);
        }
        catch(Exception exception)
        {
            // Handle failed tasks maybe
        }
    
        return tasks.Where(task => task.Status == TaskStatus.RanToCompletion).ToArray();
    }
    

    用法

    var tasks = new[]
    {
        Task.FromResult(1),
        Task.FromException<int>(new ArgumentException("fail1")),
        Task.FromException<int>(new ArgumentException("fail2"))
    };
    
    var succeed = await RejectFailedFrom(tasks);
    // [ tasks[0] ]
    
        3
  •  1
  •   CSDev    5 年前

    玩弄@Theodor Zoulias的有力和优雅 solution Task.WhenAll _ => { } )以及 Wait

    var cts = new CancellationTokenSource();
    cts.Cancel();
    var canceled = Task.Run(() => 1, cts.Token);
    
    var faulted = Task.FromException<int>(new Exception("Some Exception"));
    
    var ranToCompletion = Task.FromResult(1);
    
    var allTasks = new[] { canceled, faulted, ranToCompletion };
    
    // wait all tasks to complete regardless anything
    Task.WhenAll(allTasks).ContinueWith(_ => { }).Wait();
    
    foreach(var t in allTasks)
    {
        Console.WriteLine($"Task #{t.Id} {t.Status}");
        if (t.Status == TaskStatus.Faulted)
            foreach (var e in t.Exception.InnerExceptions)
                Console.WriteLine($"\t{e.Message}");
        if (t.Status == TaskStatus.RanToCompletion)
            Console.WriteLine($"\tResult: {t.Result}");
    }
    

    输出如下所示:

    Task #2 Canceled
    Task #1 Faulted
            Some Exception
    Task #5 RanToCompletion
            Result: 1
    
        4
  •  -1
  •   Ted Mucuzany    5 年前

    改变

    var task = Task.WhenAll(tPass1, tFail1, tFail2);
    task.Wait();
    

    var all = new Task<int>[] { tPass1, tFail1, tFail2 }
        .Where(t => t.Status == TaskStatus.RanToCompletion);
    var task = Task.WhenAll(all);
    task.Wait();
    

    Working example