Je veux vous attendent afin de jeter AggregateException, pas seulement la première Exception
Lors de l'attente d'une reproché à la tâche (celui qui a une exception), await
va renvoyer la stockées exception. Si la réserve d'exception est un AggregateException
il va renvoyer le premier et jeter le reste.
Comment pouvons-nous utiliser await
et en même temps jeter l'original AggregateException
de façon à ne pas perdre accidentellement les informations d'erreur?
Noter qu'il est bien sûr possible de penser hacky solutions pour cela (par exemple try-catch autour de la await
, puis d'appeler Task.Wait
). Je vous souhaite vraiment de trouver une solution propre. Quelle est la meilleure pratique ici?
Je pensais de l'aide personnalisé awaiter mais le haut- TaskAwaiter
contient beaucoup de magie que je ne suis pas sûr de la façon de reproduire intégralement. Il appelle interne de l'Api sur les TPL types. Je n'ai pas non voulez de reproduire tout cela.
Voici une petite repro si vous voulez jouer avec elle:
static void Main()
{
Run().Wait();
}
static async Task Run()
{
Task[] tasks = new[] { CreateTask("ex1"), CreateTask("ex2") };
await Task.WhenAll(tasks);
}
static Task CreateTask(string message)
{
return Task.Factory.StartNew(() => { throw new Exception(message); });
}
Seulement l'une des deux exceptions sont jetés dans Run
.
Noter, que d'autres questions sur un Débordement de Pile à ne pas traiter de ce problème spécifique. Soyez prudent lors de l'suggérant des doublons.
- Avez-vous vu cette entrée de blog expliquant pourquoi ils ont choisi de mettre en œuvre la gestion des exceptions pour
await
comme ils l'ont fait? blogs.msdn.com/b/pfxteam/archive/2011/09/28/10217876.aspx - Oui, merci. J'ai un peu d'accord avec ce raisonnement pour le cas général, mais mon cas d'utilisation n'est pas couverte.
- "Dans tous les cas, la Tâche de l'Exception de la propriété renvoie toujours une AggregateException qui contient toutes les exceptions, de sorte que vous pouvez attraper quel est lancée et revenir pour consulter la Tâche.Exception en cas de besoin."
Vous devez vous connecter pour publier un commentaire.
Je suis en désaccord avec l'implication dans votre question titre que
await
le comportement indésirable. Il a de sens que dans la grande majorité des scénarios. Dans unWhenAll
situation, combien de fois avez-vous vraiment besoin de savoir tous les détails de l'erreur, par opposition à un seul?La principale difficulté de la
AggregateException
est la gestion des exceptions, c'est à dire, vous perdez la capacité d'attraper un type particulier.Cela dit, vous pouvez obtenir le comportement que vous voulez avec une méthode d'extension:
UnobservedTaskException
, de l'Application des gestionnaires) au lieu de la répétition destry
/catch
blocs.UnobservedTaskException
est toujours levé pour les non observées des exceptions (il n'a tout simplement pas bloquer le processus plus). Le seul cas où vous avez observé, avalé exception estWhenAll
, et qu'il ne se produit lorsque vous avez plusieurs exceptions, dont l'une est pas d'ingestion. Tu as vraiment de essayer pour ignorer les exceptions avecawait
.throw
.await
peut masquer des exceptions sans jamais te trouver.. ou seulement après beaucoup de temps passé sur le débogage. Fourre-tout clauses utilisées à être désapprouvées - et je pense qu'elles le sont. Pourquoi les mêmes raisons s'appliquent pas àawait Task.WhenAll
?await
fait la bonne chose en ne prenant en compte qu'une seule exception à la règle.WhenAll
est la seule situation où ce ne peut pas être la meilleure solution. Lorsque j'ai utiliséWhenAll
, je n'ai presque jamais besoin de connaître toutes les exceptions, juste qu'il n'y a un exception. Doncawait
fait la bonne chose de la vaste, la vaste majorité du temps. C'est différent decatch { }
uniquement parce que le supplémentaire exceptions sont ignorés, pas tous d'entre eux.AggregateException
par l'infrastructure), toujours une seule exception directement. Les cas spéciaux commeTask.WhenAll
devriez jeter unAggregateException
ou peut-être un plus spécifiques exception commeParallelWorkJoinException
(ce qui serait enveloppez 1-les exceptions - 1 pour chaque Tâche qui a échoué).await
serait alors pas besoin de déballer une exception. Même comportement que de maintenant pour 99% des cas, des cas spéciaux obtenir évidente, un traitement spécial - droit de l'avant.AggregateException
au moins. Hésitez pas à postez votre idée de discussion. De côté: techniquement,await
ne pas déballer leAggregateException
, mais c'est un OK modèle mental.source.Exception
pourrait être une référence null lors de l'annulation.Je sais je suis en retard mais j'ai trouvé ce joli petit truc qui fait ce que vous voulez. Depuis l'ensemble des exceptions sont disponibles sur attendue de la Tâche, à l'appel de cette Tâche d'Attente ou un .Résultat de jeter un agrégat d'exception.
La Gestion Des Exceptions (Task Parallel Library)
Je pourrais en dire plus mais il serait juste de rembourrage. Jouer avec elle, il ne fonctionne pas comme ils disent. Vous avez juste à être prudent.
peut-être que vous voulez que ce
Dieu (Jon Skeet) explique attendent la gestion des exceptions
(personnellement je peur de l'attendent, mais c'est juste ma préférence)
en réponse à des commentaires (trop long pour un commentaire de réponse)
Ensuite utiliser les threads comme votre point de départ pour un analogue de l'argument que les meilleures pratiques, il y aura la source de pour ici.
Exceptions heureusement avoir avalé, à moins que vous mettre en œuvre le code pour les passer (par exemple le modèle asynchrone qui l'attendent est preumably emballage ... vous les ajoutez à un événement args objet lorsque vous soulevez un événement). Quand vous avez un scénario où vous lancez un nombre arbitraire de threads et de l'exécuter sur eux, vous n'avez aucun contrôle sur l'ordre ou le point où vous mettez fin à chaque thread. En outre, vous de ne jamais utiliser ce modèle si un message d'erreur sur l'un était pertinent à l'autre. À cet effet, il vous est fortement ce qui implique que l'exécution de la reste est completley indépendant - c'est à dire vous sont fortement ce qui implique que les exceptions à ces fils ont déjà été traitées comme des exceptions. Si vous voulez faire quelque chose au-delà de la gestion des exceptions dans ces fils dans le fils, ils se produisent dans (ce qui est bizzarre), vous devez les ajouter à un système de blocage de la collection qui est passé par référence vous ne les considérant plus comme des exceptions comme des exceptions, mais comme un élément d'information - l'utilisation concomitante de sac, enveloppez-le d'exception dans l'info dont vous avez besoin pour identifier le contexte, il est venu de qui aurait été adoptée dans le.
Ne pas confondre votre cas d'utilisation.
await
. Le 2ème contient une réponse valable. Merci. Je vais laisser les autres réponses dans quelques jours parce que j'ai envie de découvrir le mieux la solution.Je ne sais pas si je me suis permis de résumer les deux meilleures solutions (à mon avis) le problème présenté dans cette très intéressante question, les réponses de M. Stephen Cleary et M. adonthy. J'ai modifié légèrement l'API par l'ajout d'un paramètre
preserveAggregate
, dans une tentative pour être cohérent avec la construction unique-dans l'option de configuration, laConfigureAwait
. Ces configurations sont chainable, par exemple:Ici est M. Stephen Cleary du version (légèrement modifié):
Et voici M. adonthy de l' version (légèrement modifié):
Aussi loin que je peux dire que les deux implémentations sont équivalentes et excellent.
Je ne veux pas abandonner la pratique à seulement attraper les exceptions je pense. Ce qui m'amène à la suite de la méthode d'extension:
La consommation de code pourrait aller comme ceci:
Un os à tête d'exception aura le même effet que dans synchrone monde, même dans le cas où il est jeté en concomitance avec un
MyException
par hasard. L'emballage avecNotImplementedException
permet de ne pas perdre la trace de la pile d'origine.