2011-06-08 16 views
8

Estoy usando Async CTP para escribir una aplicación de consola IO pesada. Pero estoy teniendo problemas con excepciones.Manejo de excepciones asíncronas con void

public static void Main() 
{ 
    while (true) { 
    try{ 
     myobj.DoSomething(null); 
    } 
    catch(Exception){} 
    Console.Write("done"); 
    //... 
    } 
} 

//... 
public async void DoSomething(string p) 
{ 
    if (p==null) throw new InvalidOperationException(); 
    else await SomeAsyncMethod(); 
} 

Y ocurre lo siguiente: "hecho" se escribe en la consola, entonces consigo la excepción en el depurador, a continuación, presiono continuar existe mi programa.
¿Qué ofrece?

Respuesta

9

Cuando llame al DoSomething(), básicamente crea un Task debajo del capó y comienza ese Task. Como tenía una firma void, no hay un objeto Task que le devuelva la señal o que podría haber bloqueado, por lo que la ejecución se realizó directamente. Mientras tanto, la tarea arroja una excepción, que nadie está atrapando, que, sospecho, es la razón por la cual termina su programa.

creo que el comportamiento que quería es de la misma familia:

public static void Main() 
{ 
    while (true) { 
    var t = myobj.DoSomething(null); 
    t.Wait(); 
    if(t.HasException) { 
     break; 
    } 
    } 
    Console.Write("done"); 
    //... 
    } 
} 

//... 
public async Task DoSomething(string p) 
{ 
    if (p==null) throw new InvalidOperationException(); 
    else await SomeAsyncMethod(); 
} 

Esto bloqueará en cada DoSomething hasta que se hace y salir del bucle si DoSomething tiró. Por supuesto, entonces no estás haciendo nada de manera asincrónica. Pero desde el pseudo código, no puedo decir exactamente qué quieres que ocurra de forma asíncrona.

Salida principal: el uso de void para un método asíncrono significa que usted pierde la capacidad de obtener la excepción a menos que sea await ese método asíncrono. Como una llamada de sincronización, básicamente solo programa el trabajo y el resultado desaparece en el éter.

+0

No puedo llamar a t.Wait(), ya que bloquea el hilo de la consola principal, por lo que no puedo ingresar nada más, por lo que SomeAsyncMethod nunca terminará (para mi uso, consulte: http://stackoverflow.com/questions/6145246/how-to-write-c-5-async) – TDaver

+0

¡Pero lo he descubierto! No ESPERO mis tareas, las pongo en una lista, y después de cada operación IO (cuando pueden arrojar excepciones) ¡reviso la lista si alguna de las tareas falló! – TDaver

+1

Sí, generalmente es mejor iniciar todas las tareas, recopilarlas en una lista y luego en TaskEx.WhenAll (listOfTasks) .Wait() cuando desee recopilar todo el trabajo –

11

Si indica su aplicación Consola un contexto compatible con asíncrono (por ejemplo, AsyncContext (docs, source) de mi biblioteca AsyncEx), entonces usted puede capturar las excepciones que se propagan fuera de ese contexto, incluso desde async void métodos:

public static void Main() 
{ 
    try 
    { 
    AsyncContext.Run(() => myobj.DoSomething(null)); 
    } 
    catch (Exception ex) 
    { 
    Console.Error.WriteLine(ex.Message); 
    } 
    Console.Write("done"); 
} 

public async void DoSomething(string p) 
{ 
    if (p==null) throw new InvalidOperationException(); 
    else await SomeAsyncMethod(); 
} 
+4

Has restablecido el equilibrio a la Fuerza. ¡Gracias! –