JSQ*_*reD 107
我很惊讶地发现,5年后,所有答案仍然存在以下一个或多个问题:
我相信我的解决方案将解决原始问题,而不会遇到任何上述问题:
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建议:
  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.ReadLine无论如何都应该在进行呼叫之前进行同步.
gp.*_*gp. 33
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();
Gul*_*zim 27
这种方法会使用Console.KeyAvailable帮助吗?
class Sample 
{
    public static void Main() 
    {
    ConsoleKeyInfo cki = new ConsoleKeyInfo();
    do {
        Console.WriteLine("\nPress a key to display; press the 'x' key to quit.");
// Your code could perform some useful task in the following loop. However, 
// for the sake of this example we'll merely pause for a quarter second.
        while (Console.KeyAvailable == false)
            Thread.Sleep(250); // Loop until input is entered.
        cki = Console.ReadKey(true);
        Console.WriteLine("You pressed the '{0}' key.", cki.Key);
        } while(cki.Key != ConsoleKey.X);
    }
}
Eri*_*ric 10
不管怎样,你需要第二个线程.您可以使用异步IO来避免声明自己的:
如果读取返回数据,则设置事件并且主线程将继续,否则您将在超时后继续.
// 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.
}
小智 9
这对我有用.
ConsoleKeyInfo k = new ConsoleKeyInfo();
Console.WriteLine("Press any key in the next 5 seconds.");
for (int cnt = 5; cnt > 0; cnt--)
  {
    if (Console.KeyAvailable == true)
      {
        k = Console.ReadKey();
        break;
      }
    else
     {
       Console.WriteLine(cnt.ToString());
       System.Threading.Thread.Sleep(1000);
     }
 }
Console.WriteLine("The key pressed was " + k.Key);
在我找到一个在企业环境中完美运行的解决方案之前,我在这个问题上挣扎了5个月.
到目前为止,大多数解决方案的问题在于它们依赖于Console.ReadLine()之外的其他东西,并且Console.ReadLine()具有很多优点:
我的解决方案如下:
示例代码:
 InputSimulator.SimulateKeyPress(VirtualKeyCode.RETURN);
有关此技术的更多信息,包括中止使用Console.ReadLine的线程的正确技术:
.NET调用将[enter]键发送到当前进程,这是一个控制台应用程序?
当所述线程正在执行Console.ReadLine时,如何在.NET中中止另一个线程?
如果您在该Main()方法中,则不能使用await,因此您必须使用Task.WaitAny():
var task = Task.Factory.StartNew(Console.ReadLine);
var result = Task.WaitAny(new Task[] { task }, TimeSpan.FromSeconds(5)) == 0
    ? task.Result : string.Empty;
但是,C# 7.1 引入了创建异步Main()方法的可能性,因此最好Task.WhenAny()在有该选项时使用该版本:
var task = Task.Factory.StartNew(Console.ReadLine);
var completedTask = await Task.WhenAny(task, Task.Delay(TimeSpan.FromSeconds(5)));
var result = object.ReferenceEquals(task, completedTask) ? task.Result : string.Empty;
在委托中调用Console.ReadLine()很糟糕,因为如果用户未点击“ enter”,则该调用将永远不会返回。执行委托的线程将被阻塞,直到用户单击“ enter”为止,而无法取消它。
发出一系列这些调用将不会像您期望的那样运行。考虑以下内容(使用上面的示例Console类):
System.Console.WriteLine("Enter your first name [John]:");
string firstName = Console.ReadLine(5, "John");
System.Console.WriteLine("Enter your last name [Doe]:");
string lastName = Console.ReadLine(5, "Doe");
用户让第一个提示的超时时间到期,然后为第二个提示输入一个值。firstName和lastName都将包含默认值。当用户单击“ enter”时,将完成第一个 ReadLine调用,但是代码已放弃该调用,并实际上丢弃了结果。在第二的ReadLine调用将继续阻止,超时最终将到期,返回的值将再次成为默认。
顺便说一句-上面的代码中有一个错误。通过调用waitHandle.Close(),可以从工作线程下关闭事件。如果用户在超时到期后单击“ enter”,则工作线程将尝试发信号通知引发ObjectDisposedException的事件。异常是从工作线程中抛出的,如果您尚未设置未处理的异常处理程序,则该过程将终止。
| 归档时间: | 
 | 
| 查看次数: | 52944 次 | 
| 最近记录: |