Con System.Threading.Tasks.Task<TResult>
, tengo que gestionar las excepciones que podrían lanzarse. Estoy buscando la mejor manera de hacerlo. Hasta ahora, he creado una clase base que gestiona todas las excepciones no detectadas dentro de la llamada de.ContinueWith(...)
Me pregunto si hay una mejor manera de hacerlo. O incluso si es una buena forma de hacerlo.
public class BaseClass
{
protected void ExecuteIfTaskIsNotFaulted<T>(Task<T> e, Action action)
{
if (!e.IsFaulted) { action(); }
else
{
Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() =>
{
/* I display a window explaining the error in the GUI
* and I log the error.
*/
this.Handle.Error(e.Exception);
}));
}
}
}
public class ChildClass : BaseClass
{
public void DoItInAThread()
{
var context = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew<StateObject>(() => this.Action())
.ContinueWith(e => this.ContinuedAction(e), context);
}
private void ContinuedAction(Task<StateObject> e)
{
this.ExecuteIfTaskIsNotFaulted(e, () =>
{
/* The action to execute
* I do stuff with e.Result
*/
});
}
}
fuente
t
es la excepción.SynchronizationContext
, si es necesario.Puede crear una fábrica de tareas personalizada, que producirá tareas con procesamiento de manejo de excepciones integrado. Algo como esto:
using System; using System.Threading.Tasks; class FaFTaskFactory { public static Task StartNew(Action action) { return Task.Factory.StartNew(action).ContinueWith( c => { AggregateException exception = c.Exception; // Your Exception Handling Code }, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously ).ContinueWith( c => { // Your task accomplishing Code }, TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.ExecuteSynchronously ); } public static Task StartNew(Action action, Action<Task> exception_handler, Action<Task> completion_handler) { return Task.Factory.StartNew(action).ContinueWith( exception_handler, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously ).ContinueWith( completion_handler, TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.ExecuteSynchronously ); } };
Puede olvidarse del procesamiento de excepciones para Tareas producidas desde esta fábrica en su código de cliente. Al mismo tiempo, aún puede esperar la finalización de dichas tareas o usarlas en el estilo Fire-and-Forget:
var task1 = FaFTaskFactory.StartNew( () => { throw new NullReferenceException(); } ); var task2 = FaFTaskFactory.StartNew( () => { throw new NullReferenceException(); }, c => { Console.WriteLine("Exception!"); }, c => { Console.WriteLine("Success!" ); } ); task1.Wait(); // You can omit this task2.Wait(); // You can omit this
Pero para ser honesto, no estoy muy seguro de por qué desea tener un código de manejo de finalización. En cualquier caso, esta decisión depende de la lógica de su aplicación.
fuente