Cuando se inicia el método async
, captura el contexto de sincronización actual. Una forma de resolver este problema es crear su propio contexto de sincronización que capture la excepción.
El punto aquí es que los puestos de contexto de sincronización de la repetición de llamada para el grupo de subprocesos, pero con un try/catch alrededor de él:
public class AsyncSynchronizationContext : SynchronizationContext
{
public override void Send(SendOrPostCallback d, object state)
{
try
{
d(state);
}
catch (Exception ex)
{
// Put your exception handling logic here.
Console.WriteLine(ex.Message);
}
}
public override void Post(SendOrPostCallback d, object state)
{
try
{
d(state);
}
catch (Exception ex)
{
// Put your exception handling logic here.
Console.WriteLine(ex.Message);
}
}
}
En el catch
por encima de usted puede poner su lógica de manejo de excepciones.
A continuación, en cada hilo (SynchronizationContext.Current
es [ThreadStatic]
) en la que desea ejecutar async
métodos con este mecanismo, debe establecer el contexto de sincronización actual:
SynchronizationContext.SetSynchronizationContext(new AsyncSynchronizationContext());
La completa Main
ejemplo:
class Program
{
static void Main(string[] args)
{
SynchronizationContext.SetSynchronizationContext(new AsyncSynchronizationContext());
ExecuteAsyncMethod();
Console.ReadKey();
}
private static async void ExecuteAsyncMethod()
{
await AsyncMethod();
}
private static async Task AsyncMethod()
{
throw new Exception("Exception from async");
}
}
Si se espera un método asíncrono, se emite la excepción en el código que lo espera. Las excepciones no controladas se comportan de esta manera solo si el método es 'void' regresar. Esta es una razón para evitar el uso de métodos 'async void' tanto como sea posible. – svick
@svick 'async void' métodos dan como resultado un comportamiento determinista; Llamar a una función de devolución de 'Tarea' que da como resultado una excepción y no espera la tarea levantará el evento' UnobservedTaskException' en algún punto semiandomiano en el futuro cuando se ejecuta el recolector de elementos no utilizados, y si eso no hace nada, permite que el programa continúe en silencio si todo está bien. El problema no está en los métodos 'async void', simplemente exponen el problema real. Si * no * llama a una función 'que devuelve' Tarea' de un método 'async', hay muchas posibilidades de que esté haciendo algo mal. – hvd
Por cierto, solo "buena oportunidad" porque hay algunos casos excepcionales (sin juego de palabras) donde está bien descartar excepciones, pero no mucho. – hvd