2016-11-29 14 views
3

我々はこのようになりますリポジトリのコードを持っている:例外ロギングは

public class PieRepository 
{ 

    public void AddCherryPie(string incredientA) 
    { 
     try{ 
      ... 
     } 
     catch(Exception ex){ 
      log("Error in AddCherryPie(" + incredientA + ")"); 
      throw new Exception("Error in AddCherryPie(" + incredientA + ")", ex); 
     } 
    } 

    public void AddApplePie(string incredientA, string incredientB) 
    { 
     try{ 
      ... 
     } 
     catch(Exception ex){ 
      log("Error in AddApplePie(" + incredientA + "," + incerdientB + ")"); 
      throw new Exception("Error in AddApplePie(" + incredientA + "," + incredientB ")", ex); 
     } 
    } 
} 

だから、これtry -> catch -> log -> throw newリポジトリ方法や、プロジェクト内の他の重要な方法のほとんどに存在しています。

今日、このようなタイプのエラー処理をユーザーが見たことがないので、私たちはこれについて議論しましたが、主な議論は、何が起こったのかを正確に知る必要があり、私たちにまさにこのことを教えてください... これは大丈夫ですか?

編集:エラーをスローするときに元の例外メッセージが追加されました。

+0

コードは例外をキャッチしてから使用しません。代わりに、有用なデバッグ情報を含まない新しい例外をスローします。 StackTraceなどがなければ、起こったことを正確に知ることができないため、「われわれは何が起こったのか正確に知る必要がある」という議論は意味をなさない。少なくとも例外をどこかに記録してから、ユーザに有用なメッセージを提示する必要があります。 – Equalsk

+0

ログの面では、NLogや他のサードパーティのソリューションを試すことができます(NLogにはとても満足しています) – Tuco

答えて

3

新しい例外を作成しないでください。元の例外をスローするか、少なくとも内部例外として含めるだけで再利用しないでください。それ以外の場合は、スタックトレースがさらに上がってチェーンが正しくなりません。それはthrow new Exceptionの元の場所から始まります。

ベターです:

個人的に
public class PieRepository 
{ 
    public void AddCherryPie(string incredientA) 
    { 
     try{ 
      ... 
     } 
     catch(Exception ex){ 
      log("Error in AddCherryPie(" + incredientA + ")"); 
      throw 
     } 
    } 

または

public void AddApplePie(string incredientA, string incredientB) 
    { 
     try{ 
      ... 
     } 
     catch(Exception ex){ 
      log("Error in AddApplePie(" + incredientA + "," + incerdientB + ")"); 
      throw new Exception("Error in AddApplePie(" + incredientA + "," + incredientB ")", ex); // add original exception as inner exception! 
     } 
    } 
} 

、私は本当にはちょうどthrow new Exception("...", originalException)の代わりにthrowを使用することをお勧めします。元の例外をいつも捨てることで、後でフローで何をすべきかを決めることができません。ユーザーにどのようなエラーが表示されますか?プログラミングエラーよりも、データベースエラーまたは検証エラー(メッセージ「データベースが利用できない」または「原料Aが見つかりません」など)に対してアクションが異なる可能性があります。

全体的な方法が有効です。メソッドの引数とエラーのコンテキストを知っているので、早めにログを記録することをお勧めします。再スローさせることで、ユーザーにメッセージを提示するか、例外のタイプに応じて他のアクションを実行することで、UIのエラーを再度処理できます。これを読んでエラーメッセージに関するいくつかの考えについては

:あなたは本当にすべてのメソッドの使用のアスペクト指向プログラミングのためにこれをしたい場合はhttp://blog.ploeh.dk/2014/12/23/exception-messages-are-for-programmers/

さて、(AOPは、https://en.wikipedia.org/wiki/Aspect-oriented_programmingを参照してください)。この種のテクニックでは、例えば属性を使って行うことができます。たとえば、PostSharpを使用してください:http://doc.postsharp.net/exception-handling。ロギングはコードを乱雑にするべきではありません。

+0

元の例外はコードに含まれていますが、擬似コードに追加するのを忘れていました。私は「スロー」を使用しましたが、例外は十分にフレンドリーではないという議論です。 – Silencer

+0

私の意見では例外メッセージはユーザに提示すべきではありませんが、例外のタイプに依存するはずです。エラーが「MethodXXXのエラー」と表示されたときに、ユーザーがどのような措置を取ると思いますか。この方法についてはわかりません。気にしない。ユーザーは、彼が多分再試行できるかどうか、またはエラーの副作用が何であるかを知りたがっています。 –

+0

私はまた、ベースの 'Exception'クラスを全く投げないことを強くお勧めします。より具体的な例外タイプを常に使用する必要があります。そうしないと、例外を処理したい特定のcatch節を書くことができなくなります。 「例外」を投げ入れる(または作成する)正当な理由は考えられません。 – Kyle

0

これについては、いくつかの方法があります。最も単純には、ExceptionクラスのDataプロパティを使用することです:

public void AddApplePie(string incredientA, string incredientB) 
{ 
    try 
    { 
     ... 
    } 
    catch(Exception ex) 
    { 
     ex.Data["IncredientA"] = incredientA; 
     ex.Data.Add("IncredientB", incredientB); 
     throw; 
    } 
} 

また、あなたは内部例外として、元の例外を除いてその1を投げ、その後、追加の情報が含まれているカスタム例外を作成することができます。

は、次の点を考慮して、あなたのアイデアを与えるには:

public void AddApplePie(string incredientA, string incredientB) 
{ 
    try 
    { 
     ... 
    } 
    catch(Exception ex) 
    { 
     throw new PieRepositoryException("Error adding apple pie.", ex, incredientA, incredientB); 
    } 
} 

あなたのより高いレベルのコードは、特定の例外をキャッチするかの戦略を実装することができ、キャッチ:

public class PieRepositoryException : Exception 
{ 
    public PieRepositoryException(string message, Exception innerException, params string[] ingredients):base(message, innerException) 
    { 
     Ingredients = ingredients; 
    } 

    public property string[] Ingredients { get; private set; } 
} 

あなたはこれを行うことができますすべてのプロパティをログに出力するか、フォーマッタを使用してタイプに基づいてログに出力します。

+0

リポジトリのパラメータでは、intからオブジェクトまでのすべてのものが可能ですが、これらはすべて文字列として表現できるため、実際に大きな問題ではありませんが、問題の主なアイデアは 'try - > catch - >ログ - >すべてのメソッドで新しい 'をスローします。 – Silencer

1

すべてのメソッドで全く同じ動作を使用しているようですので、アスペクト指向のプログラミングフレームワークを使用することを強くお勧めします。

このようにして、カスタム例外処理ロジックを含むアスペクト(属性)を定義し、すべてのメソッドで同じボイラープレートコードを使用しないようにすることができます。

あなたは側面を使用している場合あなたのクラスは次のようになります。

public class PieRepository 
{ 
    [LogExceptions] 
    public void AddCherryPie(string incredientA) 
    { 
     ... 
    } 
} 

そして、あなたの側面は、次のようになります。あなたは側面を使用するようにメソッドを属性場合、側面はなり

public class LogExceptionsAttribute : OnExceptionAspect 
{ 
    public override void OnException(MethodExecutionArgs args) 
    { 
     // Create a log message, you can access the method info and parameters 
    } 
} 

メソッドが実行されるたびに呼び出されるため、(アプリケーションのパフォーマンスに大きな影響を与えるランタイムウィービングとは対照的に)コンパイル時ウィービングをサポートするフレームワークを必ず使用してください。

詳しくは、http://doc.postsharp.net/exception-handlingを参照してください。

+0

ありがとう、これはすばらしい答えですが、ピーター・ボンスが最初に、悪いことに私は答えとして両方をマークできません:( – Silencer