Console.ReadLine 不处理任务的 ContinueWith

Console.ReadLine not working on Task's ContinueWith

假设我有这段代码:

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)

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

如果我在 ContinueWith 中执行它,为什么 Console.ReadLine() 不起作用?

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

在你的第二种情况下 WhenAll 等待两个任务完成,但是当它们完成时你的程序完成执行。

不要忘记,如果您异步执行 Console.ReadLine(),它会阻塞执行它的 Thread,而且这次它不是主线程。它也不会被等待,如果在你的第二种情况下你将添加 Thread.Sleep(5000);Main 方法的末尾,它会等待 5 秒允许用户输入文本,但无论事实是否如此,它都会完成或者用户没有按下 'enter'.

不等待 ReadLine 的简短示例:

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

        t.Start();

        Thread.Sleep(5000);
    }

//只执行5秒

ContinueWith创建了一个新的任务,你也需要等待,所以在它后面添加一个Wait就可以了。

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

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

ReadLine 在延续之外时它 "works" 的原因是因为它阻塞了主线程,但你可能会足够快地按下回车,它仍然会在之前结束程序WriteLine 的发生取决于 tasks 花费的时间。