Выполнения нескольких асинхронных методов синхронно без кидал


У меня есть следующая задача: выполнить несколько асинхронных методов синхронно и всегда выполнять их все, даже когда один из них бросает. Генерация исключений если таковые произошли только после того, как все задачи завершены. Вот мой код:

public static async Task ContinueWithoutThrowing(this IEnumerable<Func<Task>> tasks)
    {
        var thrownExceptions = new List<Exception>();

        foreach (var task in tasks)
        {
            try
            {
                await task().ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                thrownExceptions.Add(ex);
            }
        }

        if (thrownExceptions.Any())
        {
            throw new AggregateException(thrownExceptions);
        }
    }

Использование этого кода является следующее:

Func<Task>[] tasks = { First, Second };
await tasks.ContinueWithoutThrowing().ConfigureAwait(false);

Я не уверен, что я делаю, является выполнимой, используя уже реализованные методы по задач класс как WhenAll. Но через WhenAll с ждем закидываем на первое исключение. Также не смог выяснить, какой лучше имя, чем ContinueWithoutThrowing , когда он фактически бросает, если используется ждут (но его хотят поведение). Я знаю, что этот код не обрабатывает отмены, но это не моя главная забота сейчас.



Комментарии
1 ответ

После моего первоначального ответа и исходя из ваших последующих комментариев, я бы сказал, что ваша реализация-это нормально.

Что касается имен, я бы сохранить его простым, как WhenAllCompleted

/// <summary>
/// Creates a task that will complete when all of the supplied tasks have completed synchronously.
/// </summary>
/// <param name="tasks">The tasks to wait on for completion.</param>
/// <returns>A task that represents the completion of all of the supplied tasks.</returns>
public static async Task WhenAllCompleted(this IEnumerable<Func<Task>> tasks) {
if (tasks == null) throw new ArgumentNullException("tasks");
var exceptions = new List<Exception>();
using (var e = tasks.GetEnumerator()) {
while (e.MoveNext()) {
var task = e.Current;
try {
await task();
} catch (Exception ex) {
exceptions.Add(ex);
}
}
}
if (exceptions.Any()) {
throw new AggregateException(exceptions);
}
}

Я, в основном, только добавлена нулевая проверка на представленный аргумент. Я обдумывал проверки на функция и задача возвращается как

var function = e.Current;
if (function == null) {
exceptions.Add(new ArgumentException("The tasks collection contained a null task.", "tasks"));
continue;
}
//...

но подумал, что было бы попасться на ваш более простой реализации, поэтому решил этого не делать.

Хотя вы не добавили отмены, а пока следует немного помочь с дополнительным токен отмены

/// <summary>
/// Creates a task that will complete when all of the supplied tasks have completed synchronously.
/// </summary>
/// <param name="tasks">The tasks to wait on for completion.</param>
/// <returns>A task that represents the completion of all of the supplied tasks.</returns>
public static async Task WhenAllCompleted(this IEnumerable<Func<Task>> tasks, CancellationToken token = default(CancellationToken)) {
if (tasks == null) throw new ArgumentNullException("tasks");
var exceptions = new List<Exception>();
using (var e = tasks.GetEnumerator()) {
while (e.MoveNext()) {
if (token.IsCancellationRequested) {
exceptions.Add(new OperationCanceledException("tasks collection was cancelled", token));
break;
}
try {
await e.Current();
} catch (Exception ex) {
exceptions.Add(ex);
}
}
}
if (exceptions.Any()) {
throw new AggregateException(exceptions);
}
}

2
ответ дан 22 февраля 2018 в 06:02 Источник Поделиться