Melhores Práticas

Evite vazio assíncrono

  • O único lugar onde você pode usar async void com segurança é em manipuladores de eventos. Considere o seguinte código:

     private async Task<bool> SomeFuncAsync() {
       ...
       await ...
     }
     public void button1_Click(object sender,  EventArgs e) {
       var result = SomeFuncAsync().Result;
       SomeOtherFunc();
     }
    

Assim que a chamada async for concluída, ela espera que o SynchronizationContext fique disponível. No entanto, o manipulador de eventos mantém o SynchronizationContext enquanto aguarda a conclusão do método SomeFuncAsync; causando assim uma espera circular (deadlock).

Para corrigir isso, precisamos modificar o manipulador de eventos para:

   public async void button1_Click(object sender,  EventArgs e) {
     var result = await SomeFuncAsync();
     SomeOtherFunc();
   }
  • Qualquer exceção lançada de um método async void será gerada diretamente no SynchronizationContext que estava ativo quando o método async void foi iniciado.

     private async void SomeFuncAsync() {
       throw new InvalidOperationException();
     }
     public void SomeOtherFunc() {
       try {
         SomeFuncAsync();
       }
       catch (Exception ex) {
         Console.WriteLine(ex);
         throw;
       }
     }
    

    the exception is never caught by the catch block in SomeOtherFunc.

  • Os métodos async void não fornecem uma maneira fácil de notificar o código de chamada de que eles foram concluídos

  • Métodos async void são difíceis de testar. O suporte a testes assíncronos do MSTest funciona apenas para métodos async que retornam Task ou Task<T>.