在任务中捕获exception的最好方法是什么?

使用System.Threading.Tasks.Task<TResult> ,我必须pipe理可能抛出的exception。 我正在寻找最好的方法来做到这一点。 到目前为止,我创build了一个基类来pipe理.ContinueWith(...)调用中的所有未捕获的exception.ContinueWith(...)

我想知道是否有更好的方法做到这一点。 或者即使这是一个很好的方法来做到这一点。

 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 */ }); } } 

有两种方法可以执行此操作,具体取决于所用语言的版本。

C#5.0及以上版本

您可以使用asyncawait关键字来为您简化大量的工作。

asyncawait被引入语言,以简化使用任务并行库 ,防止您必须使用ContinueWith并允许您继续以自上而下的方式编程。

正因为如此,您可以简单地使用try / catch块来捕获exception,如下所示:

 try { // Start the task. var task = Task.Factory.StartNew<StateObject>(() => { /* action */ }); // Await the task. await task; } catch (Exception e) { // Perform cleanup here. } 

请注意,封装上述的方法必须使用async关键字,以便您可以使用await

C#4.0及更低版本

您可以使用从TaskContinuationOptions枚举中获取值的ContinueWith重载处理exception,如下所示:

 // Get the task. var task = Task.Factory.StartNew<StateObject>(() => { /* action */ }); // For error handling. task.ContinueWith(t => { /* error handling */ }, context, TaskContinuationOptions.OnlyOnFaulted); 

TaskContinuationOptions枚举的OnlyOnFaulted成员表示只有在先行任务抛出exception时才应执行continuation。

当然,您可以有多个电话ContinueWithclosures同一个前提,处理非例外情况:

 // Get the task. var task = new Task<StateObject>(() => { /* action */ }); // For error handling. task.ContinueWith(t => { /* error handling */ }, context, TaskContinuationOptions.OnlyOnFaulted); // If it succeeded. task.ContinueWith(t => { /* on success */ }, context, TaskContinuationOptions.OnlyOnRanToCompletion); // Run task. task.Start(); 

您可以创build一些自定义任务工厂,这将生成embedded式exception处理处理的任务。 像这样的东西:

 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 ); } }; 

您可以忘记在客户端代码中处理从该工厂生成的任务的exception处理。 同时你还可以等待这些任务的完成或使用他们在火与忘记风格:

 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 

但是,如果说实话,我不确定你为什么要完成处理代码。 无论如何,这个决定取决于你的应用程序的逻辑。