继续执行任务<T>到任务<U>而不阻塞结果

Mik*_*sen 11 .net asynchronous

我有两个异步方法Task<int> DoInt()Task<string> DoString(int value).我有一个第三个异步方法,Task<string> DoBoth(int value)其目标是异步执行DoInt(),将其输出管道输出DoString(int)并产生结果DoBoth().

重要的限制是:

  1. 我可能没有源代码DoInt()DoString(),所以我无法修改它们.
  2. 我不想在任何时候阻止
  3. 必须将一个任务的输出(结果)作为输入传递给下一个任务
  4. 最终输出(结果)是我想要的结果 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; 
    });
}
Run Code Online (Sandbox Code Playgroud)

既然Task<string> DoString(int)已经是一个异步方法,我该如何干净地创建一个非阻塞的延续呢?实际上,我想从现有的Task创建一个延续,而不是从Func创建.

Ree*_*sey 8

您可以使用TaskExtensions.Unwrap编写整个链:

Task<string> DoBoth(int value)
{
    Task<Task<string>> task = DoInt(value).ContinueWith(valueTask => 
    {
        return DoString(valueTask.Result); 
    });

    return task.Unwrap();
}
Run Code Online (Sandbox Code Playgroud)

请注意,这假设DoInt定义为Task<int> DoInt(int value);,与您的描述不同,但遵循您的代码示例.

如果DoInt不接受int参数(与您的声明匹配),则可能变为:

Task<string> DoBoth()
{
    return DoInt().ContinueWith(t => DoString(t.Result)).Unwrap();
}
Run Code Online (Sandbox Code Playgroud)

作为额外使用的C#5和.NET 4.5(或异步目标包),您可以将其写为:

async Task<string> DoBoth(int value)
{
    int first = await DoInt(value);
    return await DoString(first);
}
Run Code Online (Sandbox Code Playgroud)