2012-03-30 20 views
6

He leído mucho sobre cómo manejar excepciones en TPL pero realmente no entiendo.manejo de excepción en Tpl

Permite tomar este código de ejemplo:

var task1 = new Task(() => { throw new Exception("Throw 1"); }); 
var task2 = task1.ContinueWith(t => Console.WriteLine("Catch 1:{0}", t.Exception.Message), 
           TaskContinuationOptions.OnlyOnFaulted); 
var task3 = task2.ContinueWith(t => Console.WriteLine("Continuation")); 

task1.Start(); 
try { 
    task1.Wait(); 
} 
catch (Exception ex) { 
    Console.WriteLine("Wait Exception: {0}", ex.Message); 
} 

esperaba que esto imprime

Catch 1 
Continuation 

pero me da

Catch 1 
Continuation 
Wait Exception 

Esto significa que la excepción todavía se considera controlada cuando el la tarea finaliza y el finalizador de la tarea acabará derribando la aplicación.

¿Cómo manejo la excepción dentro de la continuación para que el finalizador no se lance? Al mismo tiempo, quiero que la tarea permanezca en estado de error, por lo que no será posible ajustar la tarea en try/catch.


El fondo es que quiero implementar el patrón evento asíncrono como se especifica here pero con el tratamiento de errores. Mi código completo es el siguiente

public IAsyncResult Begin(AsyncCallback callback, object state, Action action) { 
    var task1 = new Task(action); 
    var task2 = task1.ContinueWith(t => HandleException(t.Exception), 
            TaskContinuationOptions.OnlyOnFaulted); 
    if (callback != null) { 
     var task3 = task2.ContinueWith(t => callback(t), 
             TaskScheduler.FromCurrentSynchronizationContext()); 
     var task4 = task3.ContinueWith(t => HandleException(t.Exception), 
             TaskContinuationOptions.OnlyOnFaulted); 
    } 

    task1.Start(); 

    return task; 
} 
+0

Pensé en llamar 't.Wait()' en un intento en la continuación e ignorando la excepción. Pero eso no funcionará, porque la continuación se puede ejecutar después de los otros lanzamientos 'Wait()'. – svick

Respuesta

3

Usted hace su espera en la tarea que falla, y si usted lee el documentation on Task.Wait cuidadosamente verá que se espera volver a lanzar la excepción en este caso.

Pero si espera en su task3 todo debería funcionar como se esperaba.

Por supuesto debe tener esto en cuenta:

Cuando se utiliza la opción OnlyOnFaulted, se garantiza que la propiedad Excepción en el antecedente no es nulo. Puede usar esa propiedad para detectar la excepción y ver qué excepción causó la falla en la tarea . Si no accede a la propiedad Exception, la excepción no se administrará. Además, si intenta acceder a la propiedad Resultado de una tarea que se ha cancelado o ha fallado, se generará una nueva excepción .

(Referencia here)

Y finalmente otra buena fuente de How to handle exceptions thrown by tasks

espero que esto ayude.

+1

Creo que lo entiendo. Esperar siempre causará una excepción incluso si tengo acceso a la propiedad .Exception. Sin embargo, el acceso a .Exception cambia la excepción para que no sea "no controlada", por lo que el finalizador de la tarea no se lanzará. Una prueba rápida parece confirmar exactamente eso. Gracias – adrianm