如何等待Task.ContinueWith内部任务完成

And*_*Gis 8 .net c# task task-parallel-library async-await

看看这段代码:

    private async Task InnerTask(bool outerTaskResult)
    {
        Console.WriteLine("2");
        await Task.Factory.StartNew(() => Thread.Sleep(10000));
        Console.WriteLine("3");
    }

    private async void Button2_Click(object sender, RoutedEventArgs e)
    {
        var task = Task.FromResult(false);
        Task<Task> aggregatedTask = task.ContinueWith(task1 => InnerTask(task1.Result));
        Console.WriteLine("1");
        await aggregatedTask;
        Console.WriteLine("4");
    }
Run Code Online (Sandbox Code Playgroud)

所需的输出是:

1
2
3
4
Run Code Online (Sandbox Code Playgroud)

但我得到:

1
2
4
3
Run Code Online (Sandbox Code Playgroud)

这可能与在不同线程上执行的InnerTask有关.

我正在使用ContinueWith,因为原始代码中的任务是以这种方式动态创建和排队的.

使用.Wait()方法(见下文)有效,但我认为这是一个坏主意,因为该方法是阻塞的.

task.ContinueWith(task1 => InnerTask(task1.Result).Wait())
Run Code Online (Sandbox Code Playgroud)

这里的正确方法是什么?

Yuv*_*kov 9

您可以使用TaskExtensions.Unwrap()(这是一个扩展方法Task<Task>)来解开outter任务并检索内部任务:

private async void Button2_Click(object sender, RoutedEventArgs e)
{
    var task = Task.FromResult(false);
    Task aggregatedTask = task.ContinueWith(task1 => InnerTask(task1.Result)).Unwrap();
    Console.WriteLine("1");
    await aggregatedTask;
    Console.WriteLine("4");
}
Run Code Online (Sandbox Code Playgroud)

请注意,为了简化整个过程,ContinueWith您可以await执行以下任务,而不是样式延续:

private async void Button2_Click(object sender, RoutedEventArgs e)
{
    var task = Task.FromResult(false);

    Console.WriteLine("1");

    var result = await task;
    await InnerTask(result);

    Console.WriteLine("4");
}
Run Code Online (Sandbox Code Playgroud)

  • @PanagiotisKanavos是的,它不是*需要*,也可以"等待"两次.两者都会做同样的事情.这当然是一种合适的方法.在C#5.0中,您实际上可以实现`Unwrap`:`public static async Task Unwrap(this Task <Task> task){等待等待任务; }(C#4.0版本实际上很烦人且很乏味.) (2认同)