List<T>.ForEach
ne joue pas particulièrement bien avec async
(LINQ-to-objects non plus, pour les mêmes raisons).
Dans ce cas, je recommande projection de chaque élément dans une opération asynchrone, et vous pouvez ensuite attendre (de manière asynchrone) qu'ils soient tous terminés.
using (DataContext db = new DataLayer.DataContext())
{
var tasks = db.Groups.ToList().Select(i => GetAdminsFromGroupAsync(i.Gid));
var results = await Task.WhenAll(tasks);
}
Les avantages de cette approche par rapport à l'octroi d'un async
délégué à ForEach
sont :
- La gestion des erreurs est plus appropriée. Les exceptions de
async void
ne peut être attrapé avec catch
cette approche propage les exceptions au niveau de la await Task.WhenAll
ce qui permet un traitement naturel des exceptions.
- Vous savez que les tâches sont terminées à la fin de cette méthode, puisqu'elle fait un
await Task.WhenAll
. Si vous utilisez async void
vous ne pouvez pas facilement savoir quand les opérations sont terminées.
- Cette approche dispose d'une syntaxe naturelle pour récupérer les résultats.
GetAdminsFromGroupAsync
On dirait qu'il s'agit d'une opération qui produit un résultat (les admins), et un tel code est plus naturel si de telles opérations peuvent retourner leurs résultats plutôt que de définir une valeur comme un effet secondaire.