在任务中捕获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及以上版本
您可以使用async
和await
关键字来为您简化大量的工作。
async
和await
被引入语言,以简化使用任务并行库 ,防止您必须使用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。
当然,您可以有多个电话ContinueWith
closures同一个前提,处理非例外情况:
// 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
但是,如果说实话,我不确定你为什么要完成处理代码。 无论如何,这个决定取决于你的应用程序的逻辑。