タイトルが分かりずらいですね、はい。
コンソールアプリ、Main関数が終了すると同時にアプリは終了します。
それはそう、当たり前。
なんですが裏のスレッドでなんか動いてるからアプリは落ちてほしくない、けどMainは終わっとるし別にawaitするべきものもない、みたいなケースは稀に良くあります。
でそういう場合はアプリが落ちないようにConsole.ReadLine();
とか仕込むのが常套手段だったりするわけです。
ただまぁ、書き捨てコードにしろConsole.ReadLine();
等で対処するのなんか嫌...となったので、ちょっと考えました。
で、出来たのが以下。
同期用と非同期用あります。 まぁ、C#7.1以降はエントリーポイントでも普通にasync/await使えるので前者いるか?って感じではあるけど一応。 上のクラス適当にコピペして、Main関数の最後に
await Exit.WaitAsync();
か
Exit.Wait();
ってすればアプリが落ちるのを防げます。Console.ReadLine();
等で対処するよりはいいでしょう。
Console.CancelKeyPress
ここから余談です。
アプリケーションを終了(キャンセル)させるのにCtrl+C
叩くのは日常茶飯事なわけですが、そのイベントはConsole.CancelKeyPress
で拾えます。
このハンドラはdelegate void ConsoleCancelEventHandler(object? sender, ConsoleCancelEventArgs e);
という型で定義されてます。
上のスクリプトから分かる通り、Ctrl+C
が叩かれたらConsoleCancelEventArgs e
のCancel
をtrue
に設定しています。
Console.CancelKeyPress += (sender, e) =>
{
e.Cancel = true;
};
このCancel
、「アプリケーションのキャンセル(Ctrl+C
)をキャンセルする」という二重否定の類のものとなってるようです。
つまり、Cancel
がfalse
ではアプリケーションが落ち、逆にtrue
ではアプリが落ちないで継続する、という具合です。
既定はfalse
。
別にアプリは落ちてくれていいのでtrue
に設定する必要なくない?という感じなのですが、
await Exit.WaitAsync();
Console.WriteLine("end.")
とかあった場合即時終了されるとConsole.WriteLine("end.")
に到達しないのでCancel=true
に設定するわけです。
と思いきや、別の理由からもCancel=true
に設定してないとマズそうです。
自分は次のような問題を踏みました。
Cancel=false
に設定して即時終了される事を期待していても、Console.WriteLine("end.")に到達する。
そしてMainの終端に到達しても、アプリが終了しない。
加えて何度Ctrl+C
を叩いても、アプリを落とせなくなる。
なんともけったいな状況に陥ります。 最終的にターミナルごと死んでもらったりしないといけなくなります。嫌すぎる。 なんでなん、という挙動ですが、とりあえずは受け入れる他ない。
というわけで即時終了してほしくてもConsole.CancelKeyPress
に触れるなら Cancel=true
に設定した方が良さそうです。
(thaks to @pCYSl5EDgo)