1
votes

Async Await avec une méthode appelant une ressource externe ou renvoyant une chaîne locale

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 commentaires

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)


3 Réponses :


4
votes

Le code que vous avez est parfait. Lorsque vous utilisez 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 .

Comme vous pouvez le voir dans cet exemple absurde

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);
}

Traduit approximativement en

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);
   }   
}

Vous utiliseriez Task.FromResult et Task.FromException lorsque vous n'avez pas ajouté le mot-clé async et que vous exécutez du code synchrone.

Dans ces cas, 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;
}


0 commentaires

0
votes

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> .


0 commentaires

2
votes

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;
}


1 commentaires

Merci John d'avoir signalé le défaut de mise en cache. J'apprécie vraiment cela!