例外が発生した場合にアプリを閉じずに処理を終了?なかったことに?したいです。
その例外の種類にもよりますが、「例外」=「予測できないもしくは予測はできても何の対応もできない」という類の例外であればなかったことにするということはあり得ません。
そんな話は聞く耳持たない、自分は自分のやり方でやる、それ以外のレスは不要ということであれば以下はスルーしてください。
.NET アプリの例外処置について、自分的に一般的と思うことを書きます。
(1) 予測可能で正しい業務フローに戻すことができる「業務エラー」(例:ユーザーの入力間違い)と、予測できないもしくは予測はできても何の対応もできない「例外」(例:DB サーバーダウン)を区別して対処。
(2) 「例外」はランタイムに拾わせてアプリケーションを停止させる。無かったことにして、ユーザが作業を続けられるようにすると、大事なデータを壊したり、強制的に停止させるより好ましからざる状況に陥るかも。
(3) よほどのことがない限り try-catch は書かない。
(4) キャッチせざるを得ない場合でも Execption はキャッチしない。キャッチせざるを得ないとしても範囲を絞る。例えば DB 関係の例外が予測される SqlException に限定して catch するとか。
(5) 間違って補足してしまった例外は throw する。(注:catch ブロックでキャッチした例外を throw するとスタックトレースが途切れるので単に throw と書く)
(6) ユーザーへの通知が必要なら、集約的例外処置を利用する。
それから、.NET 4 からは破損状態例外は catch できなくなっているそうですが、「それでも Catch (Exception e) を使用するのはよくない」ということについては以下の記事を見てください。
破損状態例外を処理する
https://docs.microsoft.com/ja-jp/archive/msdn-magazine/2009/february/clr-inside-out-handling-corrupted-state-exceptions
自分が持っている Microsoft の本に、上に書いた原則に則ったサンプルが載っていたので紹介しておきます。
データベースに INSERT する際に PK 制約違反で発生する例外のみ catch して業務エラー(2 重登録)としてユーザーに再入力を促し、その他は再 throw してランタイムに拾わせてアプリケーションを停止させるというものです。(注: 外側の try は何が起こっても finally で接続を Close してリソースリークを防ぐためのものです。内側の try - catch に注目してください)
public bool InsertAuthors()
{
var connection = new SqlConnection("接続文字列");
var command = new SqlCommand("INSERT INTO authors VALUES ('172-32-1176', 'White', ...)", connection);
try
{
connection.Open();
try
{
command.ExecuteNonQuery();
}
catch(SqlException sqle)
{
if (sqle.Number == 2627)
{
return false;
}
else
{
throw;
}
}
}
finally
{
connection.Close();
}
return true;
}
以下の記事も参考になると思います。
例外の推奨事項
https://docs.microsoft.com/ja-jp/dotnet/standard/exceptions/best-practices-for-exceptions