勇哥注: 通过这个问答贴子,可以了解一些C#历史版本对于 Task捕获异常的一些不同处。
提问者:
----------------------------------------
使用System.Threading.Tasks.Task<TResult>,我必须管理可能引发的异常。我正在寻找做到这一点的最佳方法。到目前为止,我已经创建了一个基类,该基类在调用时管理所有未捕获的异常。.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
被引入该语言以简化使用Task Parallel
Library的工作,从而避免了您必须使用ContinueWith
并允许您以自上而下的方式继续编程。
因此,您可以简单地使用try
/catch
块来捕获异常,如下所示:
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及以下
您可以使用从枚举中获取值的ContinueWith
重载来处理异常,如下所示:TaskContinuationOptions
// Get the task. var task = Task.Factory.StartNew<StateObject>(() => { /* action */ }); // For error handling. task.ContinueWith(t => { /* error handling */ }, context, TaskContinuationOptions.OnlyOnFaulted);
在OnlyOnFaulted
该成员TaskContinuationOptions
枚举指示应继续 只 当先行任务抛出异常执行。
当然,您可以有多个调用来ContinueWith
取消同一先决条件,从而处理非例外情况:
// 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();

