Le code suivant exécute M1
, M2
, M3
, M4
en parallèle. Chaque méthode peut soulever des exceptions. La méthode doit renvoyer les résultats des quatre méthodes asynchrones - soit les int renvoyés par les méthodes, soit les exceptions.
"M1: 1, M2: Excpetion...., M3: 3, M4: 4"
Comment capturer les exceptions individuelles de la tâche qui a échoué?
Par exemple, si seulement M2 a lancé une exception,
async Task<string> RunAll() { int m1result, m2result, m3result, m4result; try { var m1task = M1(); var m2task = M2(); var m3task = M3(); var m4task = M4(); // await Task.WhenAll(new Task<int>[] { m1task, m2task, m3task, m4task }); m1result = await m1task; m2result = await m2task; m3result = await m3task; m4result = await m4task; } catch (Exception ex) { // need to return the ex of the failed task. How? } // How to implement M1HasException, M2HasException, ... in the following lines? var m1msg = M1HasException ? M1ExceptionMessage : m1result.ToString(); var m2msg = M2HasException ? M2ExceptionMessage : m2result.ToString(); var m3msg = M3HasException ? M3ExceptionMessage : m3result.ToString(); var m4msg = M4HasException ? M4ExceptionMessage : m4result.ToString(); return $"M1: {m1msg}, M2: {m2msg}, M3: {m3msg}, M4: {m4msg}"; }
4 Réponses :
Chaque tâche a une propriété Status et et Exception.
Vous voudrez peut-être voir s'il a fait une faute:
if (myTask.Exception != null)
Ou s'il a excepté:
myTask.Status == TaskStatus.Faulted
Vous peut utiliser ContinueWhenAll
pour exécuter toutes les tâches, puis vérifier l'état.
Le problème est que dès que, par exemple, M2
a obtenu une exception, M3
et M4
ont cessé d'être invoqués.
Pourriez-vous encapsuler chaque wait
dans le bloc try-catch
et capturer le message d'exception le cas échéant, semble faisable ...
try { await Task.WhenAll(t1, t2, t3); } catch { }; // ^^^^^^^^^ // then same as ^ above
si vous souhaitez utiliser WhenAll
, vous pouvez attendre
pour cela et ignorer les exceptions, puis faire le même exercice que ci-dessus pour récupérer les résultats de chaque tâche ...
var results = new List<string>(); try { results.Add(await t1); } catch { results.Add("Exception"); }; try { results.Add(await t2); } catch { results.Add("Exception"); }; try { results.Add(await t3); } catch { results.Add("Exception"); }; return string.Join("|", results);
Comme l'ont souligné d'autres réponses / commentaires, une approche possible consiste à utiliser ContinueWith
ou ContinueWhenAll
. C'est une astuce intelligente car Task
a la propriété Exception
:
Obtient l'exception AggregateException qui a entraîné la fin prématurée de la tâche. Si la tâche s'est terminée avec succès ou n'a pas encore lancé de exceptions, cela renverra null.
En utilisant ContinueWith
, qu'une tâche se termine avec succès ou non, elle sera transmise comme argument à la fonction déléguée. De là, vous pouvez vérifier si une exception a été levée.
Task<string> GetStringedResult<T>(Task<T> initialTask) { return initialTask.ContinueWith(t => { return t.Exception?.InnerException.Message ?? t.Result.ToString(); }); } async Task<string> RunAll() { string m1result, m2result, m3result, m4result; var m1task = GetStringedResult(M1()); var m2task = GetStringedResult(M2()); var m3task = GetStringedResult(M3()); var m4task = GetStringedResult(M4()); m1result = await m1task; m2result = await m2task; m3result = await m3task; m4result = await m4task; return $"M1: {m1result}, M2: {m2result}, M3: {m3result}, M4: {m4result}"; }
Vous pouvez encapsuler les tâches dans un WaitAll
et attraper l ' AggregateException
( docs ),
try { Task.WaitAll(new[] { task1, task2 }, token); } catch (AggregateException ae) { foreach (var ex in ae.InnerExceptions) //Do what ever you want with the ex. }
Task.WhenAll
?J'ai essayé
Task.WhenAll ()
, cela ne semble pas aider à déterminer quelle tâche a obtenu l'exception. La question a été mise à jour.Je recommande d'examiner cette réponse: stackoverflow.com/a/5383408/5312245
Un exemple reproductible minimal serait génial ici.