5

これはそれほど問題ではありませんが、より多くのフィードバックと考えがあります。私は、社内チームを通じて徹底的にテストされたメソッドの実装を検討してきました。一般的な例外キャッチメソッドとレポートサービスを作成したいと思います。

これは「try-catch」ブロックほど簡単ではありませんが、例外をキャッチするための統一された方法を可能にします。理想的には、メソッドを実行し、失敗のコールバックを提供し、呼び出し元のメソッドからすべてのパラメーターをログに記録したいと思います。

一般的な試行-実行。

public class ExceptionHelper
{
     public static T TryExecute<T, TArgs>(Func<TArgs, T> Method, Func<TArgs, T> FailureCallBack, TArgs Args)
     {
            try
            {
                return Method(Args);
            }
            catch (Exception ex)
            {
                StackTrace stackTrace = new StackTrace();
                string method = "Unknown Method";
                if (stackTrace != null && stackTrace.FrameCount > 0)
                {
                    var methodInfo = stackTrace.GetFrame(1).GetMethod();
                    if (methodInfo != null)
                        method = string.Join(".", methodInfo.ReflectedType.Namespace, methodInfo.ReflectedType.Name, methodInfo.Name);
                }
                List<string> aStr = new List<string>();
                foreach (var prop in typeof(TArgs).GetProperties().Where(x => x.CanRead && x.CanWrite))
                {
                    object propVal = null;
                    try
                    {
                        propVal = prop.GetValue(Args, null);
                    }
                    catch
                    {
                        propVal = string.Empty;
                    }
                    aStr.Add(string.Format("{0}:{1}", prop.Name, propVal.ToString()));
                }
                string failureString = string.Format("The method '{0}' failed. {1}", method, string.Join(", ", aStr));
                //TODO: Log To Internal error system
                try
                {
                    return FailureCallBack(Args);
                }
                catch
                {
                    return default(T);
                }
            }
      }
}

私が欠点として知っていること。

  • リフレクションを使用したパフォーマンスの低下
  • MethodBase(methodInfo)は、最適化では利用できない場合があります
  • エラーハンドラのtry-catch。基本的に、エラーコールバックを回避するためのtry-catchにTryExecuteラッパーを使用できますが、スタックオーバーフローの状況が発生する可能性があります。

これがサンプル実装です

var model = new { ModelA = "A", ModelB = "B" };
return ExceptionHelper.TryExecute((Model) =>
{
     throw new Exception("Testing exception handler");
},
(Model) =>
{
    return false;
}, 
model);

考えやコメントをいただければ幸いです。

4

2 に答える 2

12

これは、さらに 2 つの/ブロックを含む、大量のコードです。あなたが私に尋ねると、さらに例外が実際の例外を覆い隠し、エラー情報が失われる可能性があるというリスクがかなりあります。catch trycatch

また、なぜreturn default(T)ですか?問題の兆候としてデフォルトまたはヌルを返すことは、通常かなりずさんです。他に何もないとしても、メソッドへの呼び出しごとに同じ条件をラップして、戻り値をチェックして応答する必要があります...別の場所で発生したエラー。

正直なところ、その使用例もかなり面倒に見えます。エラー トラップ コードにより、実際のビジネス ロジックがわかりにくくなってしまうようです。コードベース全体は一連のエラー トラップのように見え、実際のビジネス ロジックはそのもつれのどこかに隠されています。これにより、アプリケーションの実際の意図から重要な焦点が外れ、バックグラウンド インフラストラクチャの重要性 (ロギング) が最前線に置かれます。

簡素化する。

メソッド内で例外が発生した場合、一般的に 2 つの適切なオプションがあります。

  1. メソッド内で例外をキャッチ (および意味のある処理) します。
  2. 例外がスタックをバブルアップして、他の場所でキャッチされるようにします。

例外が発生したメソッドのスコープをエスケープする例外にはまったく問題はありません。実際、例外はまさにそれを行うように設計されており、何がどこで発生したかに関する有用なスタック情報を保持します。(また、意味のあるランタイム コンテキストを例外に追加すると、理由に関する情報も含まれます。)

実際、コンパイラはこれを微妙に示唆しています。たとえば、次の 2 つの方法を使用します。

public int Sum(int first, int second)
{
    // TODO: Implement this method
}

public int Product(int first, int second)
{
    throw new NotImplementedException();
}

これらのメソッドの 1 つがコンパイルされ、1 つがコンパイルされません。コンパイラ エラーは、すべてのコード パスが前のメソッドの値を返すわけではないことを示します。しかし、なぜ後者ではないのでしょうか? 例外をスローすることは、メソッドにとって完全に受け入れられる終了戦略であるためです。これは、メソッドが実行していること (実行する必要があることの1 つだけで、それ以上のことは何もないこと) を放棄し、呼び出し元のコードで問題を処理する方法です。

コードは、モデル化されているビジネス コンセプトを明確に表現する方法で読み取る必要があります。エラー処理は重要なインフラストラクチャの概念ですが、それは単なるインフラストラクチャです。コードは、モデル化されているビジネス コンセプトを明確かつ簡潔に実際に叫ぶ必要があります。インフラストラクチャの問題がその邪魔になるべきではありません。

于 2012-09-04T00:18:53.390 に答える
6

これが役立つことはめったにありません。

次の場合のみを対象とします。

  1. このメソッドには、障害が発生した場合に適切な戻り値を取得する明確な手段があります。
  2. あなたは実際にそれが起こったことを記録したいと思います。

現在、2 はあらゆる種類の例外で非常に一般的ですが、1 が真である場合もそうではありません。

1 はもちろんまれです。ほとんどの場合、指定されたパラメーターに対して手段 X によって妥当な戻り値を生成できる場合、最初に手段 Y を試行しないためです。

default(T)また、フォールバックが機能しない場合は、null またはすべてゼロを返すデフォルトの動作もあります。

これは、上記のケース 1 に「この処理が何をするかはあまり気にしないため、結果として null を返すだけのもの」がある場合、または呼び出されたメソッドが null を返さない場合にのみ機能します。その場合、null をテストします。これは、実際のエラー処理コードがそこで発生することを意味します。

全体として、ここにあるのは、実際のコードでトラップできる例外を、代わりにテスト (および場合によってはテスト + 当て推量) でキャッチする方法と、明確な場所でプログラムをダウンさせる例外です。適切なデバッグ情報を使用すると、代わりにどこで何が起こっているのかわからない状態になりますが、少なくとも何かが完全にダウンさせる前にログに記録された数十個のバグのうちの 1 つは、おそらく実際の問題です。

特定の理由で何らかの例外をキャッチした場合は、必ず例外をログに記録してください。これは、バグを見つけるのに役立つというより (発生した例外がバグである場合、そこでキャッチすべきではありません)、catch がバグを隠す可能性があるという事実をキャンセルするためのものであることに注意してください。つまり、キャンセルします。あちこちにキャッチを配置することで、意図的に奨励しているまさにその効果を引き出します。(たとえば、定期的にヒットする Web サービスが時々接続に失敗することが予想され、キャッシュされたデータを数時間続けることができます。そのため、失敗をキャッチしてキャッシュから続行します。バグがあった場合は、 Web サービスを正しくヒットしようとしないでください。非表示にしただけです)。

非対話型 (サービスまたはサーバー) のアプリで、スタックの最上位に到達したすべての例外をログに記録することも合理的です。例外に注意する人がそこにいないためです。

しかし、例外は敵ではなく、メッセンジャーです。メッセンジャーを撃たないでください。

于 2012-09-04T00:29:35.730 に答える