使用带有条件延续的任务

我对如何使用条件连续的任务有点困惑。

如果我有一个任务,然后我想继续处理成功和错误的任务,然后等待那些完成。

void FunctionThrows() {throw new Exception("faulted");} static void MyTest() { var taskThrows = Task.Factory.StartNew(() => FunctionThrows()); var onSuccess = taskThrows.ContinueWith( prev => Console.WriteLine("success"), TaskContinuationOptions.OnlyOnRanToCompleted); var onError = taskThrows.ContinueWith( prev => Console.WriteLine(prev.Exception), TaskContinuationOptions.OnlyOnFaulted); //so far, so good //this throws because onSuccess was cancelled before it was started Task.WaitAll(onSuccess, onError); } 

这是执行任务成功/失败分支的首选方式吗? 另外,我应该如何加入所有这些任务,假设我已经创建了一长串的延续,每个都有自己的error handling。

  //for example var task1 = Task.Factory.StartNew(() => ...) var task1Error = task1.ContinueWith( //on faulted var task2 = task1.ContinueWith( //on success var task2Error = task2.ContinueWith( //on faulted var task3 = task2.ContinueWith( //on success //etc 

在这些上调用WaitAll总是抛出,因为一些延续将由于TaskContinuationOptions而被取消,并且在取消的任务上调用Wait会抛出。 如何在没有获得“任务被取消”exception的情况下加入这些例外“?

我认为你的主要问题是你要告诉这两个任务“等待”你的电话

 Task.WaitAll(onSuccess, onError); 

将自动为您设置onSuccessonError延续,并将其前期任务完成执行。

如果你只是用Task.WaitAll(...)替换你的Task.WaitAll(...) taskThrows.Start(); 我相信你会得到所需的输出。

这是我放在一起的一个例子:

 class Program { static int DivideBy(int divisor) { Thread.Sleep(2000); return 10 / divisor; } static void Main(string[] args) { const int value = 0; var exceptionTask = new Task(() => DivideBy(value)); exceptionTask.ContinueWith(result => Console.WriteLine("Faulted ..."), TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.AttachedToParent); exceptionTask.ContinueWith(result => Console.WriteLine("Success ..."), TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.AttachedToParent); exceptionTask.Start(); try { exceptionTask.Wait(); } catch (AggregateException ex) { Console.WriteLine("Exception: {0}", ex.InnerException.Message); } Console.WriteLine("Press  to continue ..."); Console.ReadLine(); } } 

使用Task.WaitAny(onSuccess, onError);

这不正常吗?

看看MSDN文档,你做得很好,你正在实现的逻辑是合理的。 您唯一缺少的是将WaitAll调用包装在AggregateException包装中,如下所示:

 // Exceptions thrown by tasks will be propagated to the main thread // while it waits for the tasks. The actual exceptions will be wrapped in AggregateException. try { // Wait for all the tasks to finish. Task.WaitAll(tasks); // We should never get to this point Console.WriteLine("WaitAll() has not thrown exceptions. THIS WAS NOT EXPECTED."); } catch (AggregateException e) { Console.WriteLine("\nThe following exceptions have been thrown by WaitAll(): (THIS WAS EXPECTED)"); for (int j = 0; j < e.InnerExceptions.Count; j++) { Console.WriteLine("\n-------------------------------------------------\n{0}", e.InnerExceptions[j].ToString()); } } 

你可以在这里阅读更多: http : //msdn.microsoft.com/en-us/library/dd270695.aspx

本质上,捕获AggregatedException会使您完成WaitAll的相同操作。 它是从您的任务返回的所有exception的集合。