How to add a Timeout to Console.ReadLine()?

后端 未结 30 2559
耶瑟儿~
耶瑟儿~ 2020-11-22 04:57

I have a console app in which I want to give the user x seconds to respond to the prompt. If no input is made after a certain period of time, program logic should

相关标签:
30条回答
  • 2020-11-22 05:45
    string ReadLine(int timeoutms)
    {
        ReadLineDelegate d = Console.ReadLine;
        IAsyncResult result = d.BeginInvoke(null, null);
        result.AsyncWaitHandle.WaitOne(timeoutms);//timeout e.g. 15000 for 15 secs
        if (result.IsCompleted)
        {
            string resultstr = d.EndInvoke(result);
            Console.WriteLine("Read: " + resultstr);
            return resultstr;
        }
        else
        {
            Console.WriteLine("Timed out!");
            throw new TimedoutException("Timed Out!");
        }
    }
    
    delegate string ReadLineDelegate();
    
    0 讨论(0)
  • 2020-11-22 05:45
    // Wait for 'Enter' to be pressed or 5 seconds to elapse
    using (Stream s = Console.OpenStandardInput())
    {
        ManualResetEvent stop_waiting = new ManualResetEvent(false);
        s.BeginRead(new Byte[1], 0, 1, ar => stop_waiting.Set(), null);
    
        // ...do anything else, or simply...
    
        stop_waiting.WaitOne(5000);
        // If desired, other threads could also set 'stop_waiting' 
        // Disposing the stream cancels the async read operation. It can be
        // re-opened if needed.
    }
    
    0 讨论(0)
  • 2020-11-22 05:45

    I can't comment on Gulzar's post unfortunately, but here's a fuller example:

                while (Console.KeyAvailable == false)
                {
                    Thread.Sleep(250);
                    i++;
                    if (i > 3)
                        throw new Exception("Timedout waiting for input.");
                }
                input = Console.ReadLine();
    
    0 讨论(0)
  • 2020-11-22 05:45
    string readline = "?";
    ThreadPool.QueueUserWorkItem(
        delegate
        {
            readline = Console.ReadLine();
        }
    );
    do
    {
        Thread.Sleep(100);
    } while (readline == "?");
    

    Note that if you go down the "Console.ReadKey" route, you lose some of the cool features of ReadLine, namely:

    • Support for delete, backspace, arrow keys, etc.
    • The ability to press the "up" key and repeat the last command (this comes in very handy if you implement a background debugging console that gets a lot of use).

    To add a timeout, alter the while loop to suit.

    0 讨论(0)
  • 2020-11-22 05:46

    I may be reading too much into the question, but I am assuming the wait would be similar to the boot menu where it waits 15 seconds unless you press a key. You could either use (1) a blocking function or (2) you could use a thread, an event, and a timer. The event would act as a 'continue' and would block until either the timer expired or a key was pressed.

    Pseudo-code for (1) would be:

    // Get configurable wait time
    TimeSpan waitTime = TimeSpan.FromSeconds(15.0);
    int configWaitTimeSec;
    if (int.TryParse(ConfigManager.AppSetting["DefaultWaitTime"], out configWaitTimeSec))
        waitTime = TimeSpan.FromSeconds(configWaitTimeSec);
    
    bool keyPressed = false;
    DateTime expireTime = DateTime.Now + waitTime;
    
    // Timer and key processor
    ConsoleKeyInfo cki;
    // EDIT: adding a missing ! below
    while (!keyPressed && (DateTime.Now < expireTime))
    {
        if (Console.KeyAvailable)
        {
            cki = Console.ReadKey(true);
            // TODO: Process key
            keyPressed = true;
        }
        Thread.Sleep(10);
    }
    
    0 讨论(0)
  • 2020-11-22 05:46

    My code is based entirely on the friend's answer @JSQuareD

    But I needed to use Stopwatch to timer because when I finished the program with Console.ReadKey() it was still waiting for Console.ReadLine() and it generated unexpected behavior.

    It WORKED PERFECTLY for me. Maintains the original Console.ReadLine ()

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("What is the answer? (5 secs.)");
            try
            {
                var answer = ConsoleReadLine.ReadLine(5000);
                Console.WriteLine("Answer is: {0}", answer);
            }
            catch
            {
                Console.WriteLine("No answer");
            }
            Console.ReadKey();
        }
    }
    
    class ConsoleReadLine
    {
        private static string inputLast;
        private static Thread inputThread = new Thread(inputThreadAction) { IsBackground = true };
        private static AutoResetEvent inputGet = new AutoResetEvent(false);
        private static AutoResetEvent inputGot = new AutoResetEvent(false);
    
        static ConsoleReadLine()
        {
            inputThread.Start();
        }
    
        private static void inputThreadAction()
        {
            while (true)
            {
                inputGet.WaitOne();
                inputLast = Console.ReadLine();
                inputGot.Set();
            }
        }
    
        // omit the parameter to read a line without a timeout
        public static string ReadLine(int timeout = Timeout.Infinite)
        {
            if (timeout == Timeout.Infinite)
            {
                return Console.ReadLine();
            }
            else
            {
                var stopwatch = new Stopwatch();
                stopwatch.Start();
    
                while (stopwatch.ElapsedMilliseconds < timeout && !Console.KeyAvailable) ;
    
                if (Console.KeyAvailable)
                {
                    inputGet.Set();
                    inputGot.WaitOne();
                    return inputLast;
                }
                else
                {
                    throw new TimeoutException("User did not provide input within the timelimit.");
                }
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题