5

一連のステートメントをtry/catchでラップし、これらの問題の1つが例外を発行する場合、catch内では、どのステートメントが例外を引き起こしたかを知る方法がありません(ex.stacktraceは現在のメソッド(doit)を示しています。発信者、その発信者の発信者など。ただし、do1とdo2のどちらでもない):

function doit() {
   try {
     do1();
     do2();
     [...]
   }
   catch (Exception ex) {
     // what failed?
   }
}

一般的に、私はすべてのステートメントをラップして再スローすることにしました。

private void do1() {
  try {
     // do whatever
  } catch(Exception e) {
     // write to my error log
     throw new Exception("do1: " + e.Message, e.InnerException);
  }
}

これにより、ログにパンくずリストが残り、チェーンをアップストリームで使用できるようになります。もちろん、問題は、私が書くすべてのメソッドをこの種のコードでラップしなければならないことです。

何かが私にそれについて愚かであると教えてくれます。正しいアプローチは何ですか?

4

4 に答える 4

9

例外処理は非常に扱いにくいテーマであり、過去に人々はこれを正しく行う方法をめぐって宗教戦争を戦ってきたため、これを正しく行うのは困難です。

まず最初に:空のcatch(try { ... } catch { ... })も。も使用しないでcatch(Exception ex)ください。Exception派生クラスの唯一の目的は、発生した例外の種類に関する豊富な情報を提供することです。これにより、例外ハンドラーで意味のあることを実行できます(スレッドがクラッシュした場合は再起動し、db接続が非永続的に失敗した場合は再試行してください。その後、失敗するなど)。

人々は、コードの最も外側の部分にキャッチオールハンドラーを使用して、キャッチされなかった例外をログに記録する傾向があります。これは一種の問題ではありませんが、いずれの場合も、ユーザーにプロンプ​​トを表示するか、例外を再スローする必要がありthrowますthrow ex(これについても議論の)。

基本的に、例外が発生した場所をプログラムで気にする必要はありません。あなたはそれを扱うことができるか、できないかのどちらかです。あなたがそれを扱うことができないならば、あなたはそれを捕まえません。

補遺:この「何かできる場合はそうします。そうでない場合は、あえてその例外に触れないでください」という哲学の最も重要な理由は、(ログに記録されているかどうかに関係なく)サイレントにキャッチされた例外が非常に見つけにくいバグにつながる可能性があることです。 。ライブシステムでは、完全に注釈が付けられたスタックトレース(行番号などすべてを含む)を取得できない可能性があるため、ログファイルにプッシュするだけでは不十分な場合があります。

補遺2:整数入力を期待するテキストボックスを例にとってみましょう。ユーザーが入力を意味のある方法で処理できない文字列を指定した場合、変換例外がスローされ、その特定の例外をキャッチしてテキストボックスを古い値にリセットし、誤った入力についてユーザーに通知する可能性があります。あるいは、プログラムが例外で停止する(設計が悪い、その例外から回復できる)か、誤った入力を黙って表示し続けるが、古い値を使用する(設計が悪い、プログラムが誤解を招く)可能性があります。

于 2012-06-28T01:32:50.823 に答える
4

あなたがこれをすることに本当に売られているなら(他の人はこれがすでに悪い理由を述べています)、アスペクト指向プログラミングのアプローチを使用してください。これにより、作業が大幅に楽になり、最終的に作成および保守するコードの量が削減されます。

PostSharpを見てください。これは、この定型的なエラー処理を生成する属性でメソッド、クラス、または名前空間を装飾できるフレームワークを提供します。

于 2012-06-28T00:57:02.430 に答える
3

@Brankoはコメントでそれを釘付けにしました:例外のスタックトレースは、例外がキャッチされた場所ではなく、例外がスローされたポイントを示しています。

@ChaosPandionのコメントの+1:これは非常に、非常に、非常に悪い考えです。

于 2012-06-28T00:35:09.660 に答える
2

tryそしてcatch、私にはおそらく、最悪の設計の最新のプログラミングメカニズムの1つであるように思われます。進行中にエラーを処理する機能はなくなりました。すべてのステートメントを個別に試すなどの恐ろしいことをしない限り、単一の例外が発生した場合は、プロシージャ全体を失敗させる必要があります。回復するオプションはなくなり、可能な限り正常に失敗するだけです。

私がこれまでに見つけたこのための最良のパターンは、すべてのユーザーイベントをtry/でラップすることですcatch(毎回明示的な試行ではなく、メソッドを使用します)。元:

public static class Defines
{
   public static bool TryAction(Action pAction)
   {
      try { pAction(); return true; }
      catch(Exception exception) { PostException(exception); return false; }
   }
}

...

private void DoSomething(int pValue)
{
   ...
}

private void MyControl_MyEvent(object pSender, MyEventArgs pEventArgs)
{
   Defines.TryAction(() => DoSomething(pEventArgs.Data));
}

それを超えて、例外のないコードを書いてみてください。try例外が発生する可能性が非常に高く、正常に失敗するだけでなく、もう少しやりたい場合にのみ、明示的なsを使用してください。

于 2012-06-28T02:31:02.857 に答える