If I do await Task.WhenAll(tasks)
it throws exception if one or more tasks failed. I would like to examine each task objects manually.
Usually it is not good idea to catch(Exception)
. Is it reasonable to do it in this case? Or maybe there is another way to wait for all tasks? I cannot catch AggregateException
, because if there is just one it will be unwrapped.
How to do it correctly in async method?
The AwaitCompletion
extention method below does what you're looking for, with a more generic API. It returns a Task
, so you'll still have to await that, either via await
or Task.Wait()
or something else.
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);
}
}
}
After completion of the returned Task
value, all tasks in unfinishedTasks
will either be completed or error'd (or still going if you use Task.Wait()
with a timeout). AwaitCompletion
does not throw exceptions, and awaiting it will only throw exceptions if a timeout is reached. To retrieve exceptions, look at the tasks you passed in.
Usage:
Task[] tasksToWaitFor = ...
await tasksToWaitFor.AwaitCompletion()
foreach (var task in tasksToWaitFor)
{
Console.WriteLine("result: {}", task.GetResultOrDefault());
}
The GetResultOrDefault
extension method is important. If you hit Value
directly, it'll throw AggregateException when the task fails, OTOH GetResultOrDefault
will return null.
Swallow the exceptions momentarily with
await Task.WhenAll(tasks).ContinueWith(delegate {} )
but remember to then check all tasks individually and properly surface errors.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.