如何将任务的已取消状态传播到延续任务

时间:2011-01-25 21:24:18

标签: c# c#-4.0 .net-4.0 task-parallel-library

我在我的应用程序中使用任务并行库。我有一个任务(让我们称之为“DoSomething”)可能被取消。无论任务是否出现故障,取消或成功完成,我都会继续执行该任务以执行一些清理。

在启动此任务的代码中,我想返回一个Task对象,其状态(出错,取消,运行完成)反映了DoSomething任务的状态,但重要的是我返回的此任务不会反映此状态,直到继续任务执行。

以下是一个例子:

public Task Start(CancellationToken token)
{
    var doSomethingTask = Task.Factory.StartNew(DoSomething
                                                , token);

    var continuationTask = doSomethingTask.ContinueWith
                (
                 (antecedent) =>
                     {
                         if (antecedent.IsFaulted || antecedent.IsCanceled)
                         {
                             //Do failure-specific cleanup
                         }

   //Do general cleanup without regard to failure or success
                      }
                 );

//TODO: How do I return a Task obj which Status reflect the status of doSomethingTask,
//but will not transition to that status until continuationTask completes?
}

我可以使用TaskCompletionSource,但这看起来很糟糕。还有其他想法吗?

1 个答案:

答案 0 :(得分:7)

我认为TaskCompletionSource实际上是这种情况的理想选择。即您尝试返回Task作为完成工作的信号,但手动控制该任务何时以及如何报告其状态。您可以使用这样的扩展方法轻松隐藏此所需的锅炉板:

public static Task<T> WithCleanup<T>(this Task<T> t, Action<Task<T>> cleanup) {
    var cleanupTask = t.ContinueWith(cleanup);
    var completion = new TaskCompletionSource<T>();
    cleanupTask.ContinueWith(_ => {
        if(t.IsCanceled) {
            completion.SetCanceled();
        } else if(t.IsFaulted) {
            completion.SetException(t.Exception);
        } else {
            completion.SetResult(t.Result);
        }
    });
    return completion.Task;
}

并将其称为:

var doSomethingTask = Task.Factory
  .StartNew<object>(DoSomething, token)
  .WithCleanup(Cleanup);

唯一真正的警告是,由于没有非通用的Task,您无法使用普通的TaskCompletionSource执行此操作。