How to return AggregateException from async method

后端 未结 3 1351
野的像风
野的像风 2021-01-24 17:06

I got an async method working like an enhanced Task.WhenAll. It takes a bunch of tasks and returns when all are completed.

public async Task MyWhenA         


        
3条回答
  •  再見小時候
    2021-01-24 17:15

    async methods are designed to only every set at most a single exception on the returned task, not multiple.

    This leaves you with two options, you can either not use an async method to start with, instead relying on other means of performing your method:

    public Task MyWhenAll(Task t1, Task t2)
    {
        return Task.Delay(TimeSpan.FromMilliseconds(100))
            .ContinueWith(_ => Task.WhenAll(t1, t2))
            .Unwrap();
    }
    

    If you have a more complex method that would be harder to write without using await, then you'll need to unwrap the nested aggregate exceptions, which is tedious, although not overly complex, to do:

        public static Task UnwrapAggregateException(this Task taskToUnwrap)
        {
            var tcs = new TaskCompletionSource();
    
            taskToUnwrap.ContinueWith(task =>
            {
                if (task.IsCanceled)
                    tcs.SetCanceled();
                else if (task.IsFaulted)
                {
                    if (task.Exception is AggregateException aggregateException)
                        tcs.SetException(Flatten(aggregateException));
                    else
                        tcs.SetException(task.Exception);
                }
                else //successful
                    tcs.SetResult(true);
            });
    
            IEnumerable Flatten(AggregateException exception)
            {
                var stack = new Stack();
                stack.Push(exception);
                while (stack.Any())
                {
                    var next = stack.Pop();
                    foreach (Exception inner in next.InnerExceptions)
                    {
                        if (inner is AggregateException innerAggregate)
                            stack.Push(innerAggregate);
                        else
                            yield return inner;
                    }
                }
            }
    
            return tcs.Task;
        }
    

提交回复
热议问题