Verwenden Sie Anweisungen und warten Sie, bis die Schlüsselwörter in c # gut abgespielt sind

100

Ich habe eine Situation, in der ich asynceine Methode aufrufe, die eine IDisposableInstanz zurückgibt . Beispielsweise:

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

Nun , bevor asyncauf der Bühne war, wenn sie mit einem IDisposableArbeitsweise dieser Anruf und Code, der die „Antwort“ Variable verwendet wird, würde in einer using - Anweisung gewickelt werden.

Meine Frage ist, ob dies immer noch der richtige Ansatz ist, wenn das asyncSchlüsselwort in die Mischung geworfen wird. Funktioniert die using-Anweisung auch in beiden folgenden Beispielen wie erwartet, obwohl der Code kompiliert wird?

Beispiel 1

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

    return true;
}

Beispiel 2

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

    return true;
}
Swingdoctor
quelle

Antworten:

97

Ja, das sollte in Ordnung sein.

Im ersten Fall sagen Sie wirklich:

  • Warten Sie asynchron, bis wir die Antwort erhalten
  • Verwenden Sie es und entsorgen Sie es sofort

Im zweiten Fall sagen Sie:

  • Warten Sie asynchron, bis wir die Antwort erhalten
  • Warten Sie asynchron, bis wir die Antwort protokolliert haben
  • Entsorgen Sie die Antwort

Eine usingAnweisung in einer asynchronen Methode ist insofern "ungerade", als der DisposeAufruf in einem anderen Thread als dem ausgeführt wird, der die Ressource erworben hat (abhängig vom Synchronisationskontext usw.), aber es wird immer noch passieren ... vorausgesetzt, das, worauf Sie warten taucht natürlich immer auf oder scheitert. (Genau wie Sie nicht Disposein nicht asynchronem Code usingaufrufen, wenn Ihre Anweisung einen Aufruf einer Methode enthält, die niemals zurückgibt.)

Jon Skeet
quelle
4
Danke Jon. Während das meiste asynchrone Zeug für mich immer noch Voodoo ist, ist es ziemlich beruhigend zu sehen, wie oft es in andere .net-Funktionen integriert wird und einfach funktioniert
Swingdoctor
@JonSkeet Sollte warten, bis es in einem using(){...}Block verwendet wird, oder es ist ein Overkill oder kann in einigen Fällen die Leistung beeinträchtigen? Dient using(){...}der gleiche Zweck wie await?
Nam
1
@nam: Nein, usingund awaitdienen ganz anderen Zwecken. Beachten Sie, dass C # 8 jetzt auch asynchron entsorgt werden kann. Es lohnt sich zwar, sich des Threading-Problems bewusst zu sein, das meine Antwort hervorhebt, aber das bedeutet definitiv nicht, dass es falsch ist , usingund zu mischen await.
Jon Skeet