Utilisez des instructions et attendez que les mots clés jouent bien en c #

101

J'ai une situation où je fais un asyncappel à une méthode qui retourne et IDisposableinstance. Par exemple:

HttpResponseMessage response = await httpClient.GetAsync(new Uri("http://www.google.com"));

Maintenant, avant asyncétait sur la scène, lorsque vous travaillez avec une IDisposableinstance, cet appel et le code qui utilisait la variable "response" seraient enveloppés dans une instruction using.

Ma question est de savoir si c'est toujours la bonne approche lorsque le asyncmot-clé est jeté dans le mélange? Même si le code se compile, l'instruction using fonctionnera-t-elle toujours comme prévu dans les deux exemples ci-dessous?

Exemple 1

using(HttpResponseMessage response = await httpClient.GetAsync(new Uri("http://www.google.com")))
{
    // Do something with the response

    return true;
}

Exemple 2

using(HttpResponseMessage response = await httpClient.GetAsync(new Uri("http://www.google.com")))
{
    await this.responseLogger.LogResponseAsync(response);

    return true;
}
médecin swing
la source

Réponses:

97

Oui, ça devrait être bien.

Dans le premier cas, vous dites vraiment:

  • Attendez de manière asynchrone jusqu'à ce que nous puissions obtenir la réponse
  • Utilisez-le et jetez-le immédiatement

Dans le second cas, vous dites:

  • Attendez de manière asynchrone jusqu'à ce que nous puissions obtenir la réponse
  • Attendez de manière asynchrone jusqu'à ce que nous ayons enregistré la réponse
  • Éliminer la réponse

Une usinginstruction dans une méthode asynchrone est "étrange" en ce que l' Disposeappel peut s'exécuter dans un thread différent de celui qui a acquis la ressource (en fonction du contexte de synchronisation, etc.) mais cela se produira toujours ... en supposant ce que vous attendez se montre ou échoue, bien sûr. (Tout comme vous ne finirez pas par appeler Disposedu code non asynchrone si votre usinginstruction contient un appel à une méthode qui ne retourne jamais.)

Jon Skeet
la source
4
Merci Jon. Bien que la plupart des trucs asynchrones soient toujours vaudous pour moi, il est assez rassurant de voir à quelle fréquence ils s'intègrent à d'autres fonctionnalités .net et fonctionnent tout simplement
swingdoctor
@JonSkeet Devrait-il même être utilisé à l'intérieur d'un using(){...}bloc ou c'est exagéré ou peut-il dégrader les performances dans certains cas? A-t-il using(){...}le même objectif que await?
nam
1
@nam: Non, usinget awaitservent des objectifs totalement différents. Notez que C # 8 dispose désormais également d'une élimination asynchrone. Même s'il vaut la peine d'être conscient du problème de filetage que ma réponse met en évidence, cela ne signifie certainement pas qu'il est mal de mélanger usinget await.
Jon Skeet le