例如,假设我正在编写一个带有以下签名的方法(C#4所以没有异步关键字):
public Task Refresh();
它将调用一个方法(也返回Task
)来执行通信工作,然后运行任务延续以根据检索到的数据更新某些内部状态。 e.g:
public Task Refresh()
{
Task<MyData> commsTask = datasource.LoadData();
Task handleDataTask = commsTask.ContinueWith( HandleNewData );
return ?;
}
如果我返回handleDataTask
它的完成状态正确跟踪'刷新'操作的结果,但它没有正确报告它的启动状态。
我可以将它们包装在一个新的Task.Factory.StartNew
中,并将它们创建为子任务,但是为了链接某些任务延续而调整一个新线程似乎很浪费。
当然,使用TPL有一种简洁有效的方法吗?
答案 0 :(得分:3)
通常,Task.Status
仅用于了解最终状态。无论如何,你不能依赖任务[{1}}因为该状态可能随时改变。
由于这个事实,你返回的任务在完成之前是否具有“奇怪”状态并不重要。只有三个已完成的状态(Started
,Completed
,Canceled
)很重要。
答案 1 :(得分:0)
我做了一些进一步的研究,发现了类似的SO问题和一些博客文章:
Task chaining without TaskCompletionSource?
http://blogs.msdn.com/b/pfxteam/archive/2010/11/21/10094564.aspx
所以有一半的答案 - 您可以创建一个代表所有子任务的Task实例,而无需假脱机线程并将它们作为子任务附加:只需使用TaskCompletionSource即可。以下简单示例适用于我的上述问题而没有失败或取消处理:
public Task Refresh()
{
var refreshTaskSource = new TaskCompletionSource<object>();
Task<MyData> commsTask = datasource.LoadData();
Task handleDataTask = commsTask.ContinueWith( HandleNewData );
handleDataTask.ContinueWith( t => refreshTaskSource.SetResult(null) );
return refreshTaskSource.Task;
}
然而此方法返回的任务现在直接从TaskStatus.WaitingForActivation
转换为TaskStatus.RanToCompletion
(如果处理了这些情况,则为Faulted / Cancelled)。