我有一个控制台应用程序,我想在其中给用户 x 秒的时间来响应提示。如果经过一定时间后仍未输入任何内容,则程序逻辑应继续。我们假设超时意味着空响应。
解决这个问题的最直接方法是什么?
令我惊讶的是,五年后,所有答案仍然遭受以下一个或多个问题的困扰:
我相信我的解决方案将解决原来的问题,而不会遇到上述任何问题:
class Reader { private static Thread inputThread; private static AutoResetEvent getInput, gotInput; private static string input; static Reader() { getInput = new AutoResetEvent(false); gotInput = new AutoResetEvent(false); inputThread = new Thread(reader); inputThread.IsBackground = true; inputThread.Start(); } private static void reader() { while (true) { getInput.WaitOne(); input = Console.ReadLine(); gotInput.Set(); } } // omit the parameter to read a line without a timeout public static string ReadLine(int timeOutMillisecs = Timeout.Infinite) { getInput.Set(); bool success = gotInput.WaitOne(timeOutMillisecs); if (success) return input; else throw new TimeoutException("User did not provide input within the timelimit."); } }
当然,调用非常简单:
try { Console.WriteLine("Please enter your name within the next 5 seconds."); string name = Reader.ReadLine(5000); Console.WriteLine("Hello, {0}!", name); } catch (TimeoutException) { Console.WriteLine("Sorry, you waited too long."); }
另外,您可以使用TryXX(out)约定,如shmueli所建议:
TryXX(out)
public static bool TryReadLine(out string line, int timeOutMillisecs = Timeout.Infinite) { getInput.Set(); bool success = gotInput.WaitOne(timeOutMillisecs); if (success) line = input; else line = null; return success; }
称为如下:
Console.WriteLine("Please enter your name within the next 5 seconds."); string name; bool success = Reader.TryReadLine(out name, 5000); if (!success) Console.WriteLine("Sorry, you waited too long."); else Console.WriteLine("Hello, {0}!", name);
在这两种情况下,您都无法将呼叫Reader与普通Console.ReadLine呼叫混在一起:如果Reader超时,将会有一个挂断的ReadLine呼叫。相反,如果您要进行普通(非定时)ReadLine呼叫,只需使用Reader并忽略超时,以便它默认为无限超时。
Reader
Console.ReadLine
ReadLine
那么我提到的其他解决方案的那些问题呢?
我预见到该解决方案的唯一问题是它不是线程安全的。但是,多个线程实际上并不能同时要求用户输入,因此Reader.ReadLine无论如何都要在调用之前进行同步。
Reader.ReadLine