C# 使用TPL的任务组合和错误处理

C# 使用TPL的任务组合和错误处理,c#,.net,task-parallel-library,C#,.net,Task Parallel Library,我有一个具有以下结构的方法: public Task InitializeAsync() { var taskCompletionSource = new TaskCompletionSource<bool>(); Task firstTask = ...; // secondTask calls taskCompletionSource.TrySetResult(true) once it considers itself "done" Task

我有一个具有以下结构的方法:

public Task InitializeAsync()
{
    var taskCompletionSource = new TaskCompletionSource<bool>();

    Task firstTask = ...;

    // secondTask calls taskCompletionSource.TrySetResult(true) once it considers itself "done"
    Task secondTask = firstTask.ContinueWith(..., TaskContinuationOptions.OnlyOnRanToCompletion);

    Action<TasK> errorContinuation = x =>
        {
            taskCompletionSource.SetException(e.Exception);
        };

    firstTask.ContinueWith(errorContinuation, TaskContinuationOptions.OnlyOnFaulted);
    secondTask.ContinueWith(errorContinuation, TaskContinuationOptions.OnlyOnFaulted);

    return taskCompletionSource.Task;
}
公共任务初始化同步()
{
var taskCompletionSource=新的taskCompletionSource();
Task firstTask=。。。;
//secondTask在认为自己“完成”后调用taskCompletionSource.TrySetResult(true)
Task secondTask=firstTask.ContinueWith(…,TaskContinuationOptions.OnlyOnRanToCompletion);
操作错误继续=x=>
{
taskCompletionSource.SetException(即异常);
};
firstTask.ContinueWith(errorContinuation,TaskContinuationOptions.OnlyOnFaulted);
secondTask.ContinueWith(errorContinuation,TaskContinuationOptions.OnlyOnFaulted);
返回taskCompletionSource.Task;
}
重要的是:

  • InitializeAsync
    返回的任务在第二个任务决定完成之前不会被视为已完成
  • secondTask
    仅在
    firstTask
    成功时运行
  • firstTask
    secondTask
    失败会导致整个任务失败

我想知道的是,是否有一种更干净、更简单的方式来表达这一点,同时实现相同的功能。我使用的是.NET 4.0,但我感兴趣的是4.5是否也能让这变得更简单。

另一个选择是将两个任务创建为附加的子任务(嵌套在返回的父任务中)

在附加的子任务完成之前,父任务将不会完成。子错误被视为父错误


对于.NET 4.0,我使用了一个从到链接任务的想法,如您所述。特别是,请查看标题为的部分,然后查看。并不是说他的版本希望您传入一个返回任务的函数,而不是像您那样只传递一个方法,以
ContinueWith


另一方面,
Then
使您非常接近
SelectMany
您需要能够通过LINQ from子句链接任务。在.NET 4.5中,我提到这一点主要是作为一个语法选项,直到async/await,尽管我自己并没有实际使用它。

在4.5中,你可以通过wait/async特性和try/catch来实现这一点,只需将任务插入一个异步函数中即可。我最近遇到了同样的问题,并沿着相同的路线前进,直到我找到了由Stephen Toub撰写的博客文章,Gideon的答案链接到了这篇文章。与我最初尝试的解决方案相比,它更干净,更明显地处理了所有紧急情况。这是一个干净、通用的解决方案,我很惊讶它不在BCL中,尽管
TaskCompletionSource
确实使它的实现变得足够简单。如果您想要一个更像
ContinueWith
的签名,您必须提供重载来指定取消令牌、调度程序等。这正是我理解中需要填充的漏洞。非常感谢。