Use declarações e espere palavras-chave funcionam bem em c #

101

Eu tenho uma situação em que estou fazendo uma asyncchamada para um método que retorna e IDisposableinstância. Por exemplo:

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

Agora, antes de entrar em asynccena, ao trabalhar com uma IDisposableinstância, essa chamada e o código que usava a variável "resposta" seriam envolvidos em uma instrução using.

Minha pergunta é se essa ainda é a abordagem correta quando a asyncpalavra-chave é incluída no mix? Mesmo que o código seja compilado, a instrução using ainda funcionará conforme o esperado em ambos os exemplos abaixo?

Exemplo 1

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

    return true;
}

Exemplo 2

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

    return true;
}
swingdoctor
fonte

Respostas:

97

Sim, isso deve estar bem.

No primeiro caso, você está realmente dizendo:

  • Espere de forma assíncrona até que possamos obter a resposta
  • Use-o e descarte-o imediatamente

No segundo caso, você está dizendo:

  • Espere de forma assíncrona até que possamos obter a resposta
  • Espere de forma assíncrona até que tenhamos registrado a resposta
  • Elimine a resposta

Uma usinginstrução em um método assíncrono é "estranha" porque a Disposechamada pode ser executada em uma thread diferente daquela que adquiriu o recurso (dependendo do contexto de sincronização, etc.), mas ainda vai acontecer ... assumindo o que você está esperando sempre aparece ou falha, é claro. (Assim como você não acabará chamando Disposeum código não assíncrono se sua usinginstrução contiver uma chamada para um método que nunca retorna.)

Jon Skeet
fonte
4
Obrigado Jon. Embora a maior parte do material assíncrono ainda seja vodu para mim, é bastante reconfortante ver com que frequência ele se integra a outros recursos .net e simplesmente funciona
swingdoctor
@JonSkeet Deve esperar até mesmo ser usado dentro de um using(){...}bloco ou é um exagero ou pode degradar o desempenho em alguns casos? Tem using(){...}o mesmo propósito que await?
nam
1
@nam: Não, usinge awaitservem a propósitos totalmente diferentes. Observe que o C # 8 agora também tem descarte assíncrono. Embora valha a pena estar ciente do problema de segmentação que minha resposta destaca, isso definitivamente não significa que seja errado misturar usinge await.
Jon Skeet