✨
Console.ReadLine()を中断する
Console.ReadLineをタイムアウトや、外部の要因なんかで中断したい場合、.NETの標準APIだけでは実装できません。
てことで、つぎのようにすると実現できます。
using System.Runtime.InteropServices;
if (TryReadLine(TimeSpan.FromSeconds(3), out var line))
{
Console.WriteLine($"ReadLine was completed. : {line}");
}
else
{
Console.WriteLine($"ReadLine was interrupted.");
}
static bool TryReadLine(TimeSpan timeSpan, out string line)
{
var isRead = false;
Task.Delay(timeSpan).ContinueWith(_ =>
{
// 読み込みが未完了の場合だけ中断する。
if (!isRead)
{
const int standardInputHandle = -10;
var handle = GetStdHandle(standardInputHandle);
CancelIoEx(handle, IntPtr.Zero);
}
});
try
{
line = Console.ReadLine()!;
isRead = true;
return true;
}
catch (InvalidOperationException)
{
}
catch (OperationCanceledException)
{
}
line = default!;
return false;
}
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetStdHandle(int nStdHandle);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CancelIoEx(IntPtr handle, IntPtr lpOverlapped);
上記はタイマーでキャンセルしていますが、たとえばCancellationTokenを渡すなんかも考えられますね。
以上です。
Discussion