C# 等待所有任务而不引发异常

C# 等待所有任务而不引发异常,c#,async-await,C#,Async Await,当所有(任务)一个或多个任务失败时,它会抛出异常。我想手动检查每个任务对象 通常,捕获(异常)不是一个好主意。在这种情况下这样做合理吗?或者也许有另一种等待所有任务的方法?我无法捕获聚合异常,因为如果只有一个,它将被展开 如何在异步方法中正确执行此操作?下面的等待完成扩展方法使用更通用的API实现了您想要的功能。它返回一个任务,因此您仍然需要等待它,可以通过Wait或Task.Wait()或其他方式 using System.Collections.Generic; using System.L

当所有(任务)一个或多个任务失败时,它会抛出异常。我想手动检查每个任务对象

通常,捕获(异常)不是一个好主意。在这种情况下这样做合理吗?或者也许有另一种等待所有任务的方法?我无法捕获聚合异常,因为如果只有一个,它将被展开


如何在异步方法中正确执行此操作?

下面的
等待完成
扩展方法使用更通用的API实现了您想要的功能。它返回一个
任务
,因此您仍然需要等待它,可以通过
Wait
Task.Wait()
或其他方式

using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

public static class TaskExtensions
{
    public static Task AwaitCompletion<T>(this ICollection<Task<T>> unfinishedTasks)
    {
        int remainingCount = unfinishedTasks.Count;
        var promise = new TaskCompletionSource<ICollection<Task<T>>>();
        var finishers = unfinishedTasks.Select(x => x.ContinueWith((task, state) =>
        {
            int postCount = Interlocked.Decrement(ref remainingCount);
            if (postCount == 0)
            {
                promise.SetResult(unfinishedTasks);
            }
        }, remainingCount));

        // force evaluation
        var _ = finishers.ToList();

        return promise.Task;
    }

    /// <summary>
    /// Unlike Task.Value, this doesn't wait for completion. Hence, it also doesn't
    /// throw exceptions.
    /// </summary>
    /// <returns>Value if completed, otherwise null (or default value if a value type)</returns>
    public static T GetResultOrDefault<T>(this Task<T> self)
    {
        if (self.IsCompletedSuccessfully)
        {
            return self.Result;
        }
        else
        {
            return default(T);
        }
    }
}

GetResultOrDefault
扩展方法很重要。如果您直接点击
,当任务失败时,它将抛出AggregateException,OTOH
GetResultOrDefault
将返回null。

使用

await Task.WhenAll(tasks).ContinueWith(delegate {} )

但请记住,然后逐个检查所有任务并正确地显示错误。

“通常捕获(异常)不是一个好主意”——当然……但这并不意味着您无法捕获任何异常。异常处理的规则(实际上是指导原则)不会因为您正在使用
wait
而改变。您仍然需要知道可能会发生哪些异常,您可以处理哪些异常,并且只捕获这些异常。所以,请这样做。@Icepickle单个异常将被解包,因此它不会在所有情况下都工作。@Fabjan我的意思是“在这种情况下”,很抱歉把它放错了。@PeterDuniho我不知道会发生什么异常,因为底层实现可能会改变。我只想接受那些
RanToCompletion
的任务,并放弃失败的任务。“我不知道会发生什么异常”——那么,你需要改变这一点。您不能四处捕捉每一个异常,然后期望能够安全地继续。并非所有异常都会使您的进程处于一致、可靠的状态。
ContinueWith
是一种方法,不建议将其与
wait
结合使用。@TheodorZoulias ContinueWith的中断是什么?我承认这很难看。我希望有一个简短的选择。
ContinueWith
不会真正破坏任何东西,特别是在这种情况下,lambda是一个不可操作的。将两种不同的机制结合起来,以稍微不同的方式完成相同的事情,这不是一个好主意。async/await的发明是为了用取代ContinueWith,而不是与之共存。防止异常传播的首选方法是捕获异常。OP想要什么可能已经包含在问题中了。我相信async/await是建立在ContinueWith之上的。我不认为强制重新抛出异常以立即重新捕获它并获得更长的代码有什么意义。为什么不呢?将try/catch结果添加到可读和可维护的代码中,目的明确,没有意外。您真的想考虑一个可能的未知来源的环境
任务调度器
的影响吗,它将以任何方式调度传递给
ContinueWith的委托的执行?或者您对始终将
TaskScheduler.Default
作为
ContinueWith
的第二个参数传递的想法感到兴奋,以消除这种情况?
await Task.WhenAll(tasks).ContinueWith(delegate {} )