You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为C#控制台应用实现带倒计时的输入功能遇阻

控制台带倒计时的输入解决方案

针对你的需求——每个问题显示10秒倒计时,用户输入则终止当前倒计时跳转下一题,无输入则倒计时结束后自动跳转——下面是完整的可运行实现,解决你遇到的Console.ReadLine()无法终止、倒计时不显示的问题:

完整代码

using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    const int STD_INPUT_HANDLE = -10;

    [DllImport("kernel32.dll", SetLastError = true)]
    internal static extern IntPtr GetStdHandle(int nStdHandle);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool CancelIoEx(IntPtr handle, IntPtr lpOverlapped);

    static async Task Main(string[] args)
    {
        for (int i = 0; i < 3; i++)
        {
            Console.WriteLine($"=== 问题 {i + 1} ===");
            using var cts = new CancellationTokenSource();
            var countdownTask = DisplayCountdownAsync(cts.Token);
            
            // 将同步的Console.ReadLine包装到Task中,实现并行
            var inputTask = Task.Run(() =>
            {
                try
                {
                    return Console.ReadLine();
                }
                catch (OperationCanceledException)
                {
                    return null;
                }
            });

            // 等待输入或倒计时任意一个完成
            var completedTask = await Task.WhenAny(countdownTask, inputTask);
            
            // 取消未完成的任务
            cts.Cancel();
            
            if (completedTask == inputTask)
            {
                var userInput = await inputTask;
                Console.WriteLine($"\n你输入了: {userInput}");
                // 强制终止控制台输入的阻塞状态
                CancelIoEx(GetStdHandle(STD_INPUT_HANDLE), IntPtr.Zero);
            }
            else
            {
                Console.WriteLine("\n时间到!进入下一题");
            }

            // 收尾倒计时任务,避免未处理的取消异常
            try
            {
                await countdownTask;
            }
            catch (OperationCanceledException) { }
        }
    }

    static async Task DisplayCountdownAsync(CancellationToken token)
    {
        for (int i = 10; i > 0; i--)
        {
            token.ThrowIfCancellationRequested();
            // 用\r回到行首,实现倒计时数字实时刷新
            Console.Write($"\r{i} 秒剩余,请输入答案:");
            // 传入token,确保Delay能被及时取消
            await Task.Delay(1000, token);
        }
        token.ThrowIfCancellationRequested();
        Console.Write("\r0 秒剩余,请输入答案:");
    }
}

关键解决要点

  • 异步主线程:使用async Task Main简化异步任务的等待和管理,替代原来的同步阻塞逻辑。
  • CancellationToken联动:通过CancellationTokenSource实现倒计时和输入任务的双向取消——用户输入后立即终止倒计时,倒计时结束后终止输入等待。
  • 强制终止控制台输入:调用CancelIoEx中断Console.ReadLine()的阻塞状态,这是解决你之前Task.WhenAny后输入仍卡住的核心。
  • 实时倒计时显示:利用\r回车符回到当前行开头,覆盖原有内容实现倒计时数字的实时刷新,避免产生冗余输出。

原代码的问题分析

  1. 原方案仅用Task.Delay+ContinueWith实现超时,但没有处理任务间的取消联动,也没有实现实时倒计时的UI反馈。
  2. 直接使用Task.WhenAny后未强制终止Console.ReadLine的阻塞,导致它会持续占用输入资源,影响下一个问题的流程。

内容的提问来源于stack exchange,提问作者Klagefurt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 04:44:54