WhenAll для .NET 3.5
Я пытаюсь написать версию Task.WhenAll
для .NET 3.5 с помощью «Параллельной библиотеки задач для .NET 3.5». Это то, что я придумал. Есть ли лучший способ сделать это?
public static Task WhenAll(IEnumerable<Task> tasks)
{
var tcs = new TaskCompletionSource<object>();
var remainingTasks = tasks.ToList();
int count = remainingTasks.Count();
var exceptions = new List<Exception>();
foreach (var task in remainingTasks)
{
task.ContinueWith(t =>
{
if (Interlocked.Decrement(ref count) == 0)
{
foreach (var task1 in remainingTasks)
{
if (task1.IsFaulted)
{
exceptions.Add(task1.Exception);
}
}
if (exceptions.Any())
{
tcs.SetException(new AggregateException(exceptions));
}
else
{
tcs.SetResult(null);
}
}
});
}
return tcs.Task;
}
3 ответа
int count = remainingTasks.Count();
Так как remainingTasks
является List
, вы можете использовать свойство Count
.
var exceptions = new List<Exception>();
Эта переменная должна быть объявлена там, где она используется: в блоке if Interlocked.Decrement
.
if (task1.IsFaulted)
Это означает, что вы обрабатываете отмененные задачи так же, как успешно завершенные. Вместо этого вы можете проверить, является ли Exception
null
.
Вы также можете переписать внутренний foreach
с помощью LINQ:
var exceptions = remainingTasks
.Select(task => task.Exception)
.Where(e => e != null)
.ToList();
Мне нравится, как вы написали этот код. Всего несколько штук:
Согласованность с var
var remainingTasks = tasks.ToList(); int count = remainingTasks.Count(); var exceptions = new List<Exception>();
Почему бы не использовать var
для объявления count
? Мне кажется очевидным, что remainingTasks.Count()
будет int
, и это единственная явно типизированная переменная в вашем методе.
Нейминг
Мне не нравится task1
; вы должны предпочесть здесь имя meaninfgul, например remainingTask
. Также я не уверен в tcs
, я мог бы назвать его completionSource
.
Я поклонник неудачной методологии, поэтому я бы переключил условное выражение на:
if (Interlocked.Decrement(ref count) > 0)
{
return;
}