Tôi ngạc nhiên khi biết rằng sau 5 năm, tất cả các câu trả lời vẫn mắc phải một hoặc nhiều vấn đề sau:
- Một chức năng khác ngoài ReadLine được sử dụng, gây ra mất chức năng. (Xóa / xóa lùi / phím lên cho lần nhập trước).
- Hàm hoạt động không tốt khi được gọi nhiều lần (sinh ra nhiều luồng, nhiều ReadLine bị treo hoặc hành vi không mong muốn khác).
- Chức năng dựa trên thời gian chờ đợi. Đó là một sự lãng phí khủng khiếp vì thời gian chờ dự kiến sẽ kéo dài từ vài giây cho đến khi hết thời gian, có thể là nhiều phút. Một sự chờ đợi bận rộn kéo dài trong một khoảng thời gian như vậy là một sự ngốn tài nguyên khủng khiếp, điều này đặc biệt tồi tệ trong kịch bản đa luồng. Nếu thời gian chờ đợi được sửa đổi bằng chế độ ngủ, điều này có ảnh hưởng tiêu cực đến khả năng phản hồi, mặc dù tôi thừa nhận rằng đây có lẽ không phải là một vấn đề lớn.
Tôi tin rằng giải pháp của tôi sẽ giải quyết được vấn đề ban đầu mà không bị bất kỳ vấn đề nào ở trên:
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.");
}
}
Tất nhiên, việc gọi điện rất dễ dàng:
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.");
}
Ngoài ra, bạn có thể sử dụng TryXX(out)
quy ước, như shmueli đã đề xuất:
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;
}
Nó được gọi như sau:
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);
Trong cả hai trường hợp, bạn không thể kết hợp các cuộc gọi đến Reader
với các Console.ReadLine
cuộc gọi thông thường : nếu hết Reader
thời gian, sẽ có một ReadLine
cuộc gọi treo . Thay vào đó, nếu bạn muốn có một ReadLine
cuộc gọi bình thường (không tính thời gian) , chỉ cần sử dụng Reader
và bỏ qua thời gian chờ, để mặc định nó là thời gian chờ vô hạn.
Vì vậy, làm thế nào về những vấn đề của các giải pháp khác mà tôi đã đề cập?
- Như bạn có thể thấy, ReadLine đã được sử dụng, tránh được vấn đề đầu tiên.
- Hàm hoạt động đúng khi được gọi nhiều lần. Bất kể thời gian chờ có xảy ra hay không, chỉ một chuỗi nền sẽ chạy và chỉ có nhiều nhất một lệnh gọi tới ReadLine sẽ hoạt động. Việc gọi hàm sẽ luôn dẫn đến đầu vào mới nhất hoặc trong khoảng thời gian chờ và người dùng sẽ không phải nhấn enter nhiều lần để gửi đầu vào của mình.
- Và, rõ ràng, chức năng không dựa vào thời gian chờ đợi. Thay vào đó, nó sử dụng các kỹ thuật đa luồng thích hợp để tránh lãng phí tài nguyên.
Vấn đề duy nhất mà tôi thấy trước với giải pháp này là nó không an toàn về đường chỉ. Tuy nhiên, nhiều luồng thực sự không thể yêu cầu người dùng nhập cùng một lúc, vì vậy, nên đồng bộ hóa trước khi thực hiện cuộc gọi Reader.ReadLine
.