Console.ReadLine无法处理Task的ContinueWith

时间:2015-10-19 13:20:17

标签: c# task console-application

假设我有这段代码:

var tasks = new Task<string>[] { ToStringAsync(1) };
Task.WhenAll(tasks).ContinueWith(r => Console.WriteLine(r.Result.First()));
Console.ReadLine();

ToStringAsync具有以下实施方式:

private Task<string> ToStringAsync(object obj)
{
     return Task.FromResult(obj != null ? obj.ToString() : null);
}

这很好用,打印出来:

> 1
> _ (Wait for user interaction)

但是,如果我将Console.ReadLine()移至我的匿名操作:

var tasks = new Task<string>[] { ToStringAsync(1) };
Task.WhenAll(tasks).ContinueWith(r =>
{
    Console.WriteLine(r.Result.First());
    Console.ReadLine();
});

这应该产生与以前完全相同的输出:

> 1
> _ (Wait for user interaction)

相反,它不会等待任何输入,并且控制台应用程序会立即关闭。

为什么Console.ReadLine()ContinueWith内执行时无法正常工作?

2 个答案:

答案 0 :(得分:0)

在您的第一个示例中,它不是Task.WhenAll(tasks),而是Console.ReadLine()等待回调Task完成。方法WhenAll()不会等待.ContinueWith()因为tasks数组中不存在的单独任务。

在你的第二个场景中WhenAll等待两个任务完成,但是当你的程序完成执行时。

不要忘记,如果您异步执行Console.ReadLine(),它会阻止执行它的Thread,而且它不是主线程这次。它也是等待的,如果在第二种情况下你将Thread.Sleep(5000);添加到Main方法的末尾,它会等待5秒钟,允许用户输入文字,但之后就完成了无论用户是否按下&#39;输入&#39;

未等待ReadLine时的简短示例:

    static void Main(string[] args)
    {
        Task t = new Task(() => { Console.ReadLine(); Console.WriteLine("You pressed enter"); });

        t.Start();

        Thread.Sleep(5000);
    }

//仅执行5秒

答案 1 :(得分:0)

ContinueWith会创建一个您还需要等待的新任务,因此只需在其后添加Wait即可。

var tasks = new Task<string>[] { ToStringAsync(1) };
Task.WhenAll(tasks)
    .ContinueWith(r =>
       {
            Console.WriteLine(r.Result.First());
            Console.ReadLine();
        })
    .Wait();

现在主线程将在结束程序之前等待继续完成。

ReadLine在延续之外时它“工作”的原因是因为它阻塞了主线程,但你可能会足够快地输入,以至于它仍然会在{{1}之前结束程序根据{{​​1}}占用的时间长短发生。