我有两个异步方法Task<int> DoInt()
和Task<string> DoString(int value)
。我有第三个异步方法Task<string> DoBoth(int value)
,其目标是异步执行DoInt()
,将其输出汇总到DoString(int)
并使结果为DoBoth()
的结果。
重要的限制是:
DoInt()
或DoString()
的源代码,所以我不能
修改它们。DoBoth()
关键是我已经拥有异步的方法(即返回任务),我希望将数据从任务传递到任务,而不会阻塞,在最初的任务中返回最终结果。除了以下代码中没有阻塞之外,我可以执行以下所有操作:
代码示例:
// Two asynchronous methods from another library, i.e. can't be changed
Task<int> DoInt();
Task<string> DoString(int value);
Task<string> DoBoth()
{
return DoInt().ContinueWith<string>(intTask =>
{
// Don't want to block here on DoString().Result
return DoString(intTask.Result).Result;
});
}
由于Task<string> DoString(int)
已经是一个异步方法,我该如何干净地创建一个非阻塞的延续?实际上,我想从现有的Task创建一个延续,而不是从Func。
答案 0 :(得分:8)
您可以使用TaskExtensions.Unwrap编写整个链:
Task<string> DoBoth(int value)
{
Task<Task<string>> task = DoInt(value).ContinueWith(valueTask =>
{
return DoString(valueTask.Result);
});
return task.Unwrap();
}
请注意,这假设DoInt
定义为Task<int> DoInt(int value);
,与您的描述不同,但请遵循您的代码示例。
如果DoInt不接受int参数(与您的声明匹配),则可能会变为:
Task<string> DoBoth()
{
return DoInt().ContinueWith(t => DoString(t.Result)).Unwrap();
}
作为额外的 - 使用C#5和.NET 4.5(或异步目标包),您可以将其写为:
async Task<string> DoBoth(int value)
{
int first = await DoInt(value);
return await DoString(first);
}
答案 1 :(得分:0)
你需要像函数语言中的flatMap方法。 http://en.wikipedia.org/wiki/Monad_%28functional_programming%29#fmap_and_join