Mejores prácticas

Evite el vacío asíncrono

  • El único lugar donde puede usar async void de forma segura es en los controladores de eventos. Considere el siguiente código:

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

Una vez que se completa la llamada async, espera a que SynchronizationContext esté disponible. Sin embargo, el controlador de eventos conserva SynchronizationContext mientras espera que se complete el método SomeFuncAsync; provocando así una espera circular (interbloqueo).

Para solucionar esto, necesitamos modificar el controlador de eventos para:

   public async void button1_Click(object sender,  EventArgs e) {
     var result = await SomeFuncAsync();
     SomeOtherFunc();
   }
  • Cualquier excepción arrojada por un método async void se generará directamente en el SynchronizationContext que estaba activo cuando se inició el método async void.

     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.

  • Los métodos async void no proporcionan una manera fácil de notificar al código de llamada que han completado

  • Los métodos async void son difíciles de probar. La compatibilidad con pruebas asincrónicas de MSTest solo funciona para los métodos asincrónicos que devuelven Task o Task<T>.