Ich bin überrascht zu erfahren, dass nach 5 Jahren alle Antworten immer noch unter einem oder mehreren der folgenden Probleme leiden:
- Eine andere Funktion als ReadLine wird verwendet, was zu einem Funktionsverlust führt. (Löschen / Rücktaste / Aufwärts-Taste für vorherige Eingabe).
- Die Funktion verhält sich schlecht, wenn sie mehrmals aufgerufen wird (Laichen mehrerer Threads, viele hängende ReadLines oder anderweitig unerwartetes Verhalten).
- Die Funktion beruht auf einer Wartezeit. Dies ist eine schreckliche Verschwendung, da die Wartezeit voraussichtlich zwischen einigen Sekunden und dem Zeitlimit liegen kann, das mehrere Minuten betragen kann. Eine Wartezeit, die so lange dauert, ist ein schrecklicher Ressourcenverbrauch, der in einem Multithreading-Szenario besonders schlimm ist. Wenn das Besetzt-Warten mit einem Schlaf geändert wird, wirkt sich dies negativ auf die Reaktionsfähigkeit aus, obwohl ich zugebe, dass dies wahrscheinlich kein großes Problem ist.
Ich glaube, meine Lösung wird das ursprüngliche Problem lösen, ohne an einem der oben genannten Probleme zu leiden:
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.");
}
}
Das Anrufen ist natürlich sehr einfach:
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.");
}
Alternativ können Sie die TryXX(out)
Konvention verwenden, wie von Shmueli vorgeschlagen:
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;
}
Welches heißt wie folgt:
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);
In beiden Fällen können Sie Anrufe nicht Reader
mit normalen Console.ReadLine
Anrufen mischen : Wenn die Reader
Zeit abgelaufen ist, wird ein ReadLine
Anruf hängen bleiben . Wenn Sie stattdessen einen normalen (nicht zeitgesteuerten) ReadLine
Anruf haben möchten , verwenden Sie einfach das Reader
und lassen Sie das Zeitlimit weg, sodass standardmäßig ein unendliches Zeitlimit verwendet wird.
Wie wäre es also mit den Problemen der anderen Lösungen, die ich erwähnt habe?
- Wie Sie sehen können, wird ReadLine verwendet, um das erste Problem zu vermeiden.
- Die Funktion verhält sich bei mehrmaligem Aufruf ordnungsgemäß. Unabhängig davon, ob eine Zeitüberschreitung auftritt oder nicht, wird immer nur ein Hintergrundthread ausgeführt und höchstens ein Aufruf von ReadLine wird jemals aktiv sein. Das Aufrufen der Funktion führt immer zu der neuesten Eingabe oder zu einer Zeitüberschreitung, und der Benutzer muss nicht mehr als einmal die Eingabetaste drücken, um seine Eingabe zu senden.
- Und natürlich beruht die Funktion nicht auf einer Wartezeit. Stattdessen werden geeignete Multithreading-Techniken verwendet, um die Verschwendung von Ressourcen zu verhindern.
Das einzige Problem, das ich bei dieser Lösung sehe, ist, dass sie nicht threadsicher ist. Mehrere Threads können den Benutzer jedoch nicht gleichzeitig zur Eingabe Reader.ReadLine
auffordern. Daher sollte die Synchronisierung erfolgen, bevor Sie einen Anruf tätigen.