質問

私たちは会社のシステムの例外処理の 1 つを調査しており、いくつかの興味深い点を発見しました。

コード ブロックのほとんど (すべてではないにしても) は try/catch ブロック内にあり、catch ブロック内で新しい BaseApplicationException がスローされています。これはエンタープライズ ライブラリからのものと思われます。これを行うメリットが見当たらないので、ここで少し困っています。(いつでも別の例外を投げます)しばらくシステムを使用している開発者の1人は、そのクラスが例外の公開を担当している(そのような電子メールなどを送信する)が、彼はそれについてあまり確信が持てなかったためだと言いました。時間をかけてコードを検討した結果、コードが行っているのは環境に関する情報を収集し、それを公開するだけである、とかなり自信を持って言えます。

私の質問は次のとおりです。- すべてのコードを try { } catch { } ブロック内にラップして、新しい例外をスローするのは合理的ですか?もしそうなら、なぜですか?メリットは何ですか?

私の個人的な意見は、HttpModule を使用し、Application イベントの Error イベントにサインアップして、モジュール内で必要なことを行う方がはるかに簡単であるということです。もし私たちがこの道を進んでいたら、何かを見逃してしまうでしょうか?何か欠点はありますか?

ご意見をお待ちしております。

役に立ちましたか?

解決

一度もない1 catch (Exception ex). 。期間2. 。発生する可能性のあるさまざまな種類のエラーをすべて処理することはできません。

一度もない3 例外派生型を処理できない場合はそれをキャッチするか、(後続の例外ハンドラーで使用される) 追加情報を提供します。エラーメッセージの表示は、 ない と同じ 取り扱い エラー。

その理由をいくつか挙げてみます。

  • 捕まえて投げ直すのはコストがかかる
  • 最終的にスタックトレースが失われることになります
  • コードの信号対雑音比が低くなります。

対処方法を知っていれば、 特定の 例外 (そしてアプリケーションをエラー前の状態にリセット) を見つけて、それをキャッチします。(だからそう呼ばれています 例外 取り扱い.)

キャッチされなかった例外を処理するには、適切なイベントをリッスンします。WinForms を実行するときは、次のことをリッスンする必要があります。 System.AppDomain.CurrentDomain.UnhandledException, 、そして - あなたがやっている場合 Threading - System.Windows.Forms.Application.ThreadException. Web アプリにも同様のメカニズムがあります (System.Web.HttpApplication.Error).

アプリケーション内の(非)特定の例外でフレームワーク例外をラップする場合と同様に、 throw new MyBaseException(ex);):まったく無意味で、悪臭を放ちます。4


編集

1 一度もない @Chris がコメントで指摘したように、特にエンジニアリングに関しては非常に厳しい言葉です。最初にこの回答を書いたとき、私は原則に忠実だったことを認めます。

2,3 見る 1.

4 もしあなたがテーブルに何も新しいことを持ち込まないとしても、私はまだこれを支持します。捕まえてしまったら Exception ex さまざまな点で失敗する可能性があるメソッドの一部として、現在のメソッドはその署名にそれを反映する必要があると私は考えています。ご存知のとおり、例外はメソッド シグネチャの一部ではありません。

他のヒント

私が質問を正しく読んでいる場合、例外をインターセプトし(すべての例外をキャッチしているのか、それとも特定の例外だけをキャッチしているのか、言及していませんか?)、別の例外をスローする try / catch を実装することは一般的に悪いことであると言えます。 。

短所:

少なくとも、スタック トレース情報が失われます。表示されるスタックは、新しい例外がスローされたメソッドまでにのみ拡張されます。ここで、いくつかの有効なデバッグ情報が失われる可能性があります。

例外をキャッチしている場合は、OutOfMemory や StackOverflow などの重要な例外をそれほど重要ではない例外でマスクし、おそらく破棄されるべきプロセスが実行されたままになる危険があります。

考えられる利点:

非常に特殊なケースでは、あまりデバッグ値のない例外 (データベースから返される例外など) を取得し、処理しているオブジェクトの ID など、より多くのコンテキストを追加する例外でラップすることができます。

ただし、ほとんどの場合、これは悪臭であるため、使用には注意が必要です。

通常、例外をキャッチする必要があるのは、その場所で実行できる現実的な何か (リカバリ、ロールバック、プラン B への移行など) がある場合のみです。どうすることもできない場合は、そのままチェーンを通過させてください。新しい例外をキャッチしてスローする必要があるのは、元の例外を拡張してデバッグに役立つ特定の有用なデータがその場所に存在する場合のみです。

私は、try/catch ブロックを使用し、例外を再スローしてはならないという学派の出身です。エラーが発生する可能性のあるコードを実行している場合は、それを処理し、ログに記録し、何かを返す必要があります。例外の再スローは、アプリケーションのライフサイクルの後半で再ログすることのみを目的としています。

HttpModule を使用して例外を処理する方法に関する興味深い投稿を次に示します。 http://blogs.msdn.com/rahulso/archive/2008/07/13/how-to-use-httpmodules-to-troubleshoot-your-asp-net-application.aspx そして http://blogs.msdn.com/rahulso/archive/2008/07/18/asp-net-how-to-write-error-messages-into-a-text-file-using-a-simple-httpmodule。 aspx

チェックアウト エルマ. 。それはあなたが話していることを行います。非常によく。

ライブラリを作成するときは、呼び出し元が処理できる例外の数を常に減らすようにしています。たとえば、SQL データベースに接続するリポジトリ コンポーネントについて考えてみましょう。SQL クライアント例外から無効なキャスト例外まで、理論的にはスローされる例外が大量にあります。これらの多くは明確に文書化されており、コンパイル時に説明できます。そこで、できる限り多くの例外をキャッチし、単一の例外タイプ (RepositoryException など) に配置し、その例外がコール スタックにロールアップされるようにします。

元の例外は保持されるため、元の例外を診断できます。しかし、呼び出し元は、コードに大量の異なる catch ブロックを散りばめるのではなく、単一の例外タイプを処理することだけを考慮する必要があります。

もちろん、これにはいくつかの問題があります。最も注目すべき点は、呼び出し元がこれらの例外の一部を処理できる場合、RepositoryException をルートにして、それを処理するために内部例外のタイプをオンにする必要があることです。これは、単一の例外タイプに対して単一の catch ブロックを使用するよりもクリーンではありません。しかし、それはそれほど問題ではないと思います。

スローされた例外は例外として実装されるべきではなかったように思えます。

いずれにせよ、この BaseApplicationException は一般的な汎用例外であるため、よりコンテキスト固有の例外をスローするのが良いと思います。したがって、データベースからエンティティを取得しようとすると、EntityNotFoundException が必要になる場合があります。こうすることで、デバッグ時に実際の問題を見つけるために内部例外やスタック トレースを検索する必要がなくなります。この BaseApplicationException が例外に関する情報を収集している場合 (内部例外の追跡など)、これは問題にはなりません。

コード内で実際に例外が発生している場所にこれ以上近づけない場合にのみ、HttpModule を使用します。BaseApplicationException のエラー情報に依存する巨大な switch ステートメントである HttModule OnError イベントは実際には必要ありません。

結論として、問題の根本をすぐに示すより具体的な例外を与えることができる場合には、さまざまな例外をスローする価値があります。

私の経験から言えば、例外をキャッチし、サーバー (?) オブジェクトにエラーを追加します。これにより、.NET は必要なことをすべて実行し、例外を表示できるようになります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top