J'ai besoin d'appeler une async
méthode dans un catch
bloc avant de lancer à nouveau l'exception (avec sa trace de pile) comme ceci:
try
{
// Do something
}
catch
{
// <- Clean things here with async methods
throw;
}
Mais malheureusement, vous ne pouvez pas utiliser await
dans un bloc catch
ou finally
. J'ai appris que c'est parce que le compilateur n'a aucun moyen de revenir en arrière dans un catch
bloc pour exécuter ce qui se trouve après votre await
instruction ou quelque chose comme ça ...
J'ai essayé d'utiliser Task.Wait()
pour remplacer await
et j'ai eu une impasse. J'ai cherché sur le Web comment éviter cela et j'ai trouvé ce site .
Comme je ne peux pas changer les async
méthodes et que je ne sais pas si elles utilisent ConfigureAwait(false)
, j'ai créé ces méthodes qui prennent un Func<Task>
qui démarre une méthode asynchrone une fois que nous sommes sur un thread différent (pour éviter un blocage) et attend son achèvement:
public static void AwaitTaskSync(Func<Task> action)
{
Task.Run(async () => await action().ConfigureAwait(false)).Wait();
}
public static TResult AwaitTaskSync<TResult>(Func<Task<TResult>> action)
{
return Task.Run(async () => await action().ConfigureAwait(false)).Result;
}
public static void AwaitSync(Func<IAsyncAction> action)
{
AwaitTaskSync(() => action().AsTask());
}
public static TResult AwaitSync<TResult>(Func<IAsyncOperation<TResult>> action)
{
return AwaitTaskSync(() => action().AsTask());
}
Ma question est donc la suivante: pensez-vous que ce code est correct?
Bien sûr, si vous avez des améliorations ou connaissez une meilleure approche, je vous écoute! :)
la source
await
dans un bloc catch est en fait autorisée depuis C # 6.0 (voir ma réponse ci-dessous)Réponses:
Vous pouvez déplacer la logique en dehors du
catch
bloc et relancer l'exception après, si nécessaire, en utilisantExceptionDispatchInfo
.De cette façon, lorsque l'appelant inspecte la
StackTrace
propriété de l'exception , il enregistre toujours où à l'intérieurTaskThatFails
elle a été lancée.la source
ExceptionDispatchInfo
au lieu deException
(comme dans la réponse de Stephen Cleary)?Exception
, vous perdez tout le précédentStackTrace
?Vous devez savoir que depuis C # 6.0, il est possible d'utiliser
await
incatch
andfinally
blocks, donc vous pouvez en fait faire ceci:Les nouvelles fonctionnalités de C # 6.0, y compris celle que je viens de mentionner, sont répertoriées ici ou sous forme de vidéo ici .
la source
Si vous avez besoin d'utiliser
async
des gestionnaires d'erreurs, je vous recommande quelque chose comme ceci:Le problème avec le blocage synchrone sur le
async
code (quel que soit le thread sur lequel il s'exécute) est que vous bloquez de manière synchrone. Dans la plupart des scénarios, il est préférable d'utiliserawait
.Mise à jour: puisque vous devez relancer, vous pouvez utiliser
ExceptionDispatchInfo
.la source
throw exception;
dans l'if
instruction, la trace de la pile sera perdue.Nous avons extrait l'excellente réponse de hvd à la classe utilitaire réutilisable suivante dans notre projet:
On l'utiliserait comme suit:
N'hésitez pas à améliorer le nommage, nous l'avons gardé intentionnellement verbeux. Notez qu'il n'est pas nécessaire de capturer le contexte à l'intérieur du wrapper car il est déjà capturé dans le site d'appel, par conséquent
ConfigureAwait(false)
.la source