web-dev-qa-db-fra.com

Task.Result est-il identique à .GetAwaiter.GetResult ()?

Je lisais récemment un code qui utilise beaucoup de méthodes asynchrones, mais qui doit parfois les exécuter de manière synchrone. Le code fait:

Foo foo = GetFooAsync(...).GetAwaiter().GetResult();

Est-ce la même chose que

Foo foo = GetFooAsync(...).Result;

?

204
Jay Bazuzi

Plutôt. Une petite différence cependant: si la Task échoue, GetResult() lève simplement l'exception directement, alors que Task.Result lève une AggregateException. Cependant, à quoi sert-il d'utiliser l'un ou l'autre lorsque c'est async? La meilleure option est d'utiliser await.

De plus, vous n'êtes pas censé utiliser GetResult(). Il est conçu pour être utilisé uniquement par le compilateur, pas pour vous. Mais si vous ne voulez pas la AggregateException ennuyeuse, utilisez-la.

122
It'sNotALie.

Task.GetAwaiter().GetResult() est préférable à Task.Wait et Task.Result car il propage des exceptions plutôt que de les encapsuler dans une AggregateException. Cependant, les trois méthodes peuvent entraîner des problèmes d'interblocage et doivent être évitées en faveur de async/await.

La citation ci-dessous explique pourquoi Task.Wait et Task.Result ne contiennent pas simplement le comportement de propagation d'exception de Task.GetAwaiter().GetResult() (en raison d'une "barre de compatibilité très élevée").

Comme je l’ai mentionné précédemment, nous avons une barre de compatibilité très élevée, ce qui évite d’interrompre les modifications. En tant que tel, Task.Wait conserve son comportement d'origine d'emballage toujours. Cependant, vous pouvez vous trouver dans certaines situations avancées dans lesquelles vous souhaitez un comportement similaire au blocage synchrone utilisé par Task.Wait, mais dans lequel vous souhaitez que l'exception d'origine soit propagée non encapsulée plutôt que d'être encapsulée dans une AggregateException. Pour ce faire, vous pouvez cibler directement le serveur en attente de la tâche. Lorsque vous écrivez «await task;», le compilateur traduit cela en utilisation de la méthode Task.GetAwaiter(), qui renvoie une instance contenant une méthode GetResult(). Lorsqu'il est utilisé sur une tâche défaillante, GetResult() propage l'exception d'origine (c'est ainsi que “await task;” obtient son comportement). Vous pouvez donc utiliser «task.GetAwaiter().GetResult()» si vous souhaitez appeler directement cette logique de propagation.

https://blogs.msdn.Microsoft.com/pfxteam/2011/09/28/task-exception-handling-in-net-4-5/

"GetResult" signifie en fait "vérifier la tâche pour les erreurs"

En général, je fais de mon mieux pour éviter le blocage synchrone sur une tâche asynchrone. Cependant, il y a une poignée de situations dans lesquelles je viole cette directive. Dans ces conditions rares, ma méthode préférée est GetAwaiter().GetResult() car elle préserve les exceptions de tâches au lieu de les encapsuler dans une AggregateException.

http://blog.stephencleary.com/2014/12/a-tour-of-task-part-6-results.html

66
Nitin Agarwal

https://github.com/aspnet/Security/issues/59

"Une dernière remarque: évitez autant que possible d'utiliser Task.Result et Task.Wait comme Elles encapsulent toujours l'exception interne dans un AggregateException et remplacent le message par un message générique (une ou plusieurs erreurs se sont produites). , ce qui rend le débogage plus difficile. Même si la version synchrone ne doit pas être utilisée aussi souvent, vous devriez vivement envisager d’utiliser plutôt Task.GetAwaiter().GetResult(). "

61
scyuo

Une autre différence réside dans le fait que la fonction async renvoie uniquement Task au lieu de Task<T>, vous ne pouvez pas utiliser

GetFooAsync(...).Result;

Tandis que 

GetFooAsync(...).GetAwaiter().GetResult();

fonctionne encore.

Je sais que l'exemple de code dans la question concerne le cas Task<T>, mais la question est posée de manière générale. 

26
Nuri Tasdemir

Si une tâche échoue, l'exception est à nouveau levée lorsque le code de continuation appelle waiter.GetResult (). Plutôt que d'appeler GetResult, nous pourrions simplement accéder à la propriété Result de la tâche. L'avantage d'appeler GetResult est que si la tâche échoue, l'exception est levée directement sans être encapsulée dans AggregateException, ce qui permet des blocs d'interception plus simples et plus nets.

Pour les tâches non génériques, GetResult () a une valeur de retour vide. Sa fonction utile est alors uniquement de renvoyer des exceptions.

source: c # 7.0 en quelques mots

0
Ali Abdollahi

Comme déjà mentionné si vous pouvez utiliser await. Si vous devez exécuter le code de manière synchrone, comme vous mentionnez .GetAwaiter().GetResult(), .Result ou .Wait() constitue un risque de blocage, comme beaucoup l'ont indiqué dans des commentaires/réponses. Comme la plupart d’entre nous aiment les oneliners, vous pouvez les utiliser pour .Net 4.5<

Acquérir une valeur via une méthode asynchrone:

var result = Task.Run(() => asyncGetValue()).Result;

Appeler de manière synchronisée une méthode asynchrone

Task.Run(() => asyncMethod()).Wait();

Aucun problème d'interblocage ne se produira en raison de l'utilisation de Task.Run.

La source:

https://stackoverflow.com/a/32429753/3850405

0
Ogglas