Je me suis toujours demandé si j'effectuais correctement l'attente asynchrone et je ne trouvais rien expliquant mon scénario et si la façon dont j'ai codé ma (mes) méthode (s) affecterait mon application.
J'ai une méthode qui appellera une ressource externe en utilisant un HttpClient si une variable locale n'est pas encore remplie, si la variable locale est définie, je renvoie la variable.
Voici un exemple:
return Task.FromResult(foo);
3 Réponses :
Le code que vous avez est parfait. Lorsque vous utilisez Comme vous pouvez le voir dans cet exemple absurde Traduit approximativement en Vous utiliseriez Dans ces cas, async
, le compilateur a déjà implémenté toute la plomberie nécessaire pour renvoyer une tâche via l'implémentation générée par le compilateur d'une IAsyncStateMachine .
private void MoveNext()
{
bool result;
try
{
result = true;
}
catch (Exception exception)
{
<>1__state = -2;
<>t__builder.SetException(exception);
return;
}
<>1__state = -2;
<>t__builder.SetResult(result);
}
public Task<bool> DoSomeInterfaceAsync()
{
try
{
// return a completed task
return Task.FromResult(DoSomethingThatMightThrow());
}
catch (Exception e)
{
// Add the exception to the task
return Task.FromException<bool>(e);
}
}
Task.FromResult et
Task.FromException
lorsque vous n'avez pas ajouté le mot-clé async
et que vous exécutez du code synchrone. Task.FromResult
renvoie une tâche terminée et Task.FromException
ajoutera l'exception à la Tâche comme le ferait le framework pour les exceptions lancées dans une méthode async
[AsyncStateMachine(typeof(<DoSomething>d__0))]
public Task<bool> DoSomething()
{
<DoSomething>d__0 stateMachine = default(<DoSomething>d__0);
stateMachine.<>t__builder = AsyncTaskMethodBuilder<bool>.Create();
stateMachine.<>1__state = -1;
AsyncTaskMethodBuilder<bool> <>t__builder = stateMachine.<>t__builder;
<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
Si vous avez marqué une méthode comme async
, vous devez renvoyer le résultat, pas la Tâche
ou la Task
. Le compilateur s'occupera du reste.
Task.FromResult
est généralement requis lorsque la méthode n'est pas marquée comme async
mais que le type de méthode renvoyé est Task
ou Task < T>
.
La logique de mise en cache est légèrement défectueuse. Pendant le temps où la requête http est en cours, foo
est laissé vide, et si une autre méthode appelle GetFooDataAsync ()
pendant ce temps, la requête http sera répétée. Dans l'idéal, le cache ne devrait se remplir qu'une seule fois.
Pour assurer une et une seule invocation de la tâche, mettez en cache la tâche elle-même, pas le résultat, et attendez-la simplement chaque fois que vous voulez obtenir le résultat. Une deuxième ou troisième attente n'invoquera plus la méthode, elle accédera simplement au résultat existant.
private static Task<string> foo = null; private static async Task<string> GetFooDataAsync() { async Task<string> GetFooDataInternal() { var response = await myHttpClient.GetFooAsync(); return response.data; } if (foo == null) foo = GetFooDataInternal(); return await foo; }
Merci John d'avoir signalé le défaut de mise en cache. J'apprécie vraiment cela!
Non, tu ne devrais pas. Le compilateur fera le travail pour vous.
La chaîne foo que vous retournez est encapsulée dans une tâche par le compilateur. Pas besoin d'utiliser Task.FromResult
BTW vous n'avez pas renvoyé la variable - seule la valeur de la variable est renvoyée (sous forme de copie)