8

Todos, hay muchas preguntas sobre el tema anterior, pero creo que esto es lo suficientemente diferente como para justificar una nueva pregunta. Tengo el siguiente Task y una continuación para tratar con una variedad de tareas Status; TaskStatus.RanToCompletion, TaskStatus.Canceled y, por supuesto, AggregateException a través de TaskStatus.Faulted. El código es el siguienteTPL y Exception Handling

Task<bool> asyncTask = Task.Factory.StartNew<bool>(() => 
    asyncMethod(uiScheduler, token, someBoolean), token); 

asyncTask.ContinueWith(task => 
{ 
    // Check task status. 
    switch (task.Status) 
    { 
     // Handle any exceptions to prevent UnobservedTaskException.    
     case TaskStatus.RanToCompletion: 
      if (asyncTask.Result) 
      { 
       // Do stuff... 
      } 
      break; 
     case TaskStatus.Faulted: 
      if (task.Exception != null) 
       mainForm.progressRightLabelText = task.Exception.InnerException.Message; 
      else 
       mainForm.progressRightLabelText = "Operation failed!"; 
     default: 
      break; 
    } 
} 

Todo esto funciona bien, pero me preocupa si estoy o no estoy haciendo bien, ya que existe la posibilidad de una AggregateException ser arrojado desde el interior de la continuación - ¿entonces qué?

No quiero Wait en mi asyncTask ni la continuación ya que esto bloqueará el retorno al subproceso UI. Para la captura de excepciones emitidas desde dentro de una continuación no se puede decir que tengo que hacer algo como esto seguramente

Task parentTask = Task.Factory.startNew(() => 
    { 
     Task<bool> asyncTask = Task.Factory.StartNew<bool>(() => 
      asyncMethod(uiScheduler, token, someBoolean), token); 

     Task continueTask = asyncTask.ContinueWith(task => 
      { 
       // My continuation stuff... 
      } 

     try 
     { 
      continueTask.Wait(); 
     } 
     catch(AggregateException aggEx) 
     { 
      // Some handling here... 
     } 
    }); 

sería esto incluso trabajar? ¿Cuál es la mejor práctica aquí?

Como siempre, gracias por su tiempo.

+0

He visto tareas que "se ejecutaron por completo" cuando en realidad arrojaron una AggregateException. Ese tipo de manejo de errores no funciona. ¿Por qué no usar un try/catch? –

+0

¿Quiere decir en el método que se llama en el hilo de fondo, o en el método de delegado de continuación real? – MoonKnight

Respuesta

12

Usted puede uso tradicional try/catch dentro de sus delegados que mira para el AggregateException o se pueden encadenar en continuaciones específicas que sólo alguna vez se ejecutará si el antecedente ha criticado el uso de la opción TaskContinuationOptions.OnlyOnFaulted. El último enfoque permite definir flujos de trabajo de tareas muy limpios. Por ejemplo:

Task myRootTask = ....; 

myRootTask.ContinueWith(rootAntecdent => 
{ 
    // this will only be executed if the antecedent completed successfully, no need to check for faults 
}, 
TaskContinuationOptions.OnlyOnRanToCompletion); 

myRootTask.ContinueWith(rootAntecedent => 
{ 
    // this will only be executed if the antecedent faulted, observe exception and handle accordingly 
}, 
TaskContinuationOptions.OnlyOnFaulted); 
2

Msdn tiene un bastante bien escrito "cómo" sobre el tema: here

Usted se dará cuenta de que sólo tiene que utilizar a) bloque try/catch(AggregateException, luego filtrar la excepción que saben cómo manejar en ae.Handle(lambda) y hacer la parada de aplicación si quedan algunos que no son manejables.

+0

Conozco ejemplos como los que proporciona su enlace y no tengo ningún problema con el manejo de la recepción _de esta manera_. Mi problema es cómo manejar las excepciones lanzadas desde las continuaciones sin encerrar al delegado de continuación completo con una captura de prueba, y de nuevo esta podría ser la única forma. Quiero saber cuál es la mejor solución para el código del mundo real, no la mejor práctica del código de juguete de Microsoft. Aclamaciones. – MoonKnight

+0

+1 para el enlace. Muy útil – SleepyBoBos

+0

El OP quiere saber cómo hacer esto sin usar Wait. Todos los ejemplos Espere la tarea. Pruebe este enlace [http://msdn.microsoft.com/en-us/library/dd997415.aspx]. –