我在我的应用程序中使用任务并行库。我有一个任务(让我们称之为“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,但这看起来很糟糕。还有其他想法吗?
答案 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
执行此操作。