我对如何使用条件Continuations的任务感到困惑。
如果我有任务,然后我想继续处理成功和错误的任务,然后等待那些完成。
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);
}
这是执行任务成功/失败分支的首选方式吗?另外,我应该如何加入所有这些任务,假设我创建了一长串延续,每个都有自己的错误处理。
//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
会抛出。
如何在没有得到“任务被取消”例外的情况下加入这些例外“?
答案 0 :(得分:10)
我认为你的主要问题是你通过拨打
告诉这两项任务“等待”Task.WaitAll(onSuccess, onError);
onSuccess 和 onError 延续会自动为您设置,并且会在的前期任务完成后执行。
如果您只是将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<int>(() => 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 <Enter> to continue ...");
Console.ReadLine();
}
}
答案 1 :(得分:0)
这不正常吗?
查看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相同的功能。它是从您的任务返回的所有异常的集合。
答案 2 :(得分:0)
使用Task.WaitAny(onSuccess, onError);