在How to interrupt Console.ReadLine to figure out to interrupt a Console.ReadlLine
(and Console.ReadKey
) 之后,我遇到了以下行为(我不知道这是否是 Windows、.NET 框架或诸如此类的错误):当我使用CancelIoEx
取消 a ReadKey
(或ReadLine
),它成功地取消了读取(即中断调用并且线程继续),但似乎读取操作仍在控制台中发生(完成后将被忽略)。
难道我做错了什么?它是 Windows/.NET 中的错误吗?我应该执行其他操作来停止实际读取吗?
如何重现:
- 我正在使用带有 .NET Framework 4.7.2 的控制台项目(这也将在 .NET5.0 上重现)。
- 我正在运行以下代码:
class Program
{
const int STD_INPUT_HANDLE = -10;
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr GetStdHandle(int nStdHandle);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CancelIoEx(IntPtr handle, IntPtr lpOverlapped);
private static void InterruptReadLine()
{
var handle = GetStdHandle(STD_INPUT_HANDLE);
bool success = CancelIoEx(handle, IntPtr.Zero);
}
private static ConsoleKey? ReadHiddenKey()
{
ConsoleKey? result = null;
try
{
result = Console.ReadKey(true).Key;
}
// This is interrupted on Dispose.
catch (InvalidOperationException) { }
catch (OperationCanceledException) { }
return result;
}
static void Main(string[] args)
{
Task task = Task.Delay(2000).ContinueWith(_ =>
{
Console.WriteLine("Interrupting...");
InterruptReadLine();
});
Console.WriteLine("Read key1");
var key1 = ReadHiddenKey();
Console.WriteLine("Read key2");
var key2 = ReadHiddenKey();
Console.WriteLine($"Keys: {key1}, {key2}");
}
}
- 等待 2 秒,然后单击一个键(该键被忽略),然后单击另一个键(将被写入)。'a' 然后 'b' 的输出:
Read key1
Interrupting...
Read key2
Keys: , B
- 我希望第一次实际读取 (for
key2
) 不会被忽略(即,输出会说Keys: , A
,我将没有机会单击“b”)。 - 请注意,如果我在控制台中更改某些内容(更改其大小或最小化/最大化),它将按预期运行:2 秒后,它会中断,我更改大小,单击
a
并完成。无需额外的按键输入。
请注意,在尝试使用它时,我也遇到了以下行为:
- 更改为
try
_ReadHiddenKey
var str = Console.ReadLine();
result = ConsoleKey.Enter;
Console.WriteLine("Read: " + str);
Console.ReadKey();
在第二个之前添加ReadHiddenKey
。
写入abc
then enter 然后再1234
enter 的结果是:
Read key1
Interrupting...
Read key2
abc
1234
Read: 234
Keys: , Enter
证明行为是第一个Console.ReadLine()
抛出异常,但照常继续(因此我写的第一行是“吞下”)。