W przypadku System.Threading.Tasks.Task<TResult>
muszę zarządzać wyjątkami, które mogą zostać wyrzucone. Szukam najlepszego sposobu, żeby to zrobić. Do tej pory utworzyłem klasę bazową, która zarządza wszystkimi nieprzechwyconymi wyjątkami wewnątrz wywołania.ContinueWith(...)
Zastanawiam się, czy jest na to lepszy sposób. Lub nawet jeśli to dobry sposób na zrobienie tego.
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
*/
});
}
}
źródło
t
jest wyjątkiem.SynchronizationContext
, w razie potrzeby.Możesz utworzyć niestandardową fabrykę zadań, która będzie generować zadania z osadzonym przetwarzaniem obsługi wyjątków. Coś takiego:
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 ); } };
Możesz zapomnieć o przetwarzaniu wyjątków dla zadań utworzonych z tej fabryki w kodzie klienta. Jednocześnie możesz jeszcze poczekać na ukończenie takich Zadań lub korzystać z nich w stylu odpal i zapomnij:
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
Ale szczerze mówiąc, nie jestem pewien, dlaczego chcesz mieć kod obsługujący uzupełnianie. W każdym razie ta decyzja zależy od logiki twojej aplikacji.
źródło