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

后端 未结 30 2558
耶瑟儿~
耶瑟儿~ 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:47

    Isn't this nice and short?

    if (SpinWait.SpinUntil(() => Console.KeyAvailable, millisecondsTimeout))
    {
        ConsoleKeyInfo keyInfo = Console.ReadKey();
    
        // Handle keyInfo value here...
    }
    
    0 讨论(0)
  • 2020-11-22 05:49

    I came to this answer and end up doing:

        /// <summary>
        /// Reads Line from console with timeout. 
        /// </summary>
        /// <exception cref="System.TimeoutException">If user does not enter line in the specified time.</exception>
        /// <param name="timeout">Time to wait in milliseconds. Negative value will wait forever.</param>        
        /// <returns></returns>        
        public static string ReadLine(int timeout = -1)
        {
            ConsoleKeyInfo cki = new ConsoleKeyInfo();
            StringBuilder sb = new StringBuilder();
    
            // if user does not want to spesify a timeout
            if (timeout < 0)
                return Console.ReadLine();
    
            int counter = 0;
    
            while (true)
            {
                while (Console.KeyAvailable == false)
                {
                    counter++;
                    Thread.Sleep(1);
                    if (counter > timeout)
                        throw new System.TimeoutException("Line was not entered in timeout specified");
                }
    
                cki = Console.ReadKey(false);
    
                if (cki.Key == ConsoleKey.Enter)
                {
                    Console.WriteLine();
                    return sb.ToString();
                }
                else
                    sb.Append(cki.KeyChar);                
            }            
        }
    
    0 讨论(0)
  • 2020-11-22 05:50

    Simple threading example to solve this

    Thread readKeyThread = new Thread(ReadKeyMethod);
    static ConsoleKeyInfo cki = null;
    
    void Main()
    {
        readKeyThread.Start();
        bool keyEntered = false;
        for(int ii = 0; ii < 10; ii++)
        {
            Thread.Sleep(1000);
            if(readKeyThread.ThreadState == ThreadState.Stopped)
                keyEntered = true;
        }
        if(keyEntered)
        { //do your stuff for a key entered
        }
    }
    
    void ReadKeyMethod()
    {
        cki = Console.ReadKey();
    }
    

    or a static string up top for getting an entire line.

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

    This worked for me.

    ConsoleKeyInfo k = new ConsoleKeyInfo();
    Console.WriteLine("Press any key in the next 5 seconds.");
    for (int cnt = 5; cnt > 0; cnt--)
      {
        if (Console.KeyAvailable)
          {
            k = Console.ReadKey();
            break;
          }
        else
         {
           Console.WriteLine(cnt.ToString());
           System.Threading.Thread.Sleep(1000);
         }
     }
    Console.WriteLine("The key pressed was " + k.Key);
    
    0 讨论(0)
  • 2020-11-22 05:54

    .NET 4 makes this incredibly simple using Tasks.

    First, build your helper:

       Private Function AskUser() As String
          Console.Write("Answer my question: ")
          Return Console.ReadLine()
       End Function
    

    Second, execute with a task and wait:

          Dim askTask As Task(Of String) = New TaskFactory().StartNew(Function() AskUser())
          askTask.Wait(TimeSpan.FromSeconds(30))
          If Not askTask.IsCompleted Then
             Console.WriteLine("User failed to respond.")
          Else
             Console.WriteLine(String.Format("You responded, '{0}'.", askTask.Result))
          End If
    

    There's no trying to recreate ReadLine functionality or performing other perilous hacks to get this working. Tasks let us solve the question in a very natural way.

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

    Much more contemporary and Task based code would look something like this:

    public string ReadLine(int timeOutMillisecs)
    {
        var inputBuilder = new StringBuilder();
    
        var task = Task.Factory.StartNew(() =>
        {
            while (true)
            {
                var consoleKey = Console.ReadKey(true);
                if (consoleKey.Key == ConsoleKey.Enter)
                {
                    return inputBuilder.ToString();
                }
    
                inputBuilder.Append(consoleKey.KeyChar);
            }
        });
    
    
        var success = task.Wait(timeOutMillisecs);
        if (!success)
        {
            throw new TimeoutException("User did not provide input within the timelimit.");
        }
    
        return inputBuilder.ToString();
    }
    
    0 讨论(0)
提交回复
热议问题