2

私のテクニカルリードは、この例外メカニズムを主張しています。

try
{
    DoSth();
}
catch (OurException)
{
    throw;
}
catch (Exception ex)
{
    Util.Log(ex.Message, "1242"); // 1242 is unique to this catch block
    throw new OurException(ex);
}

1242は、OurException以外の例外を処理するcatchメソッドの識別子です。プロジェクト内のすべてのcatchブロックには一意の識別子が必要です。これにより、ログを確認することで例外が発生した場所を知ることができます。

すべてのメソッドについて、OurExceptionをキャッチしてスローする必要があります。他のタイプの例外がスローされた場合は、ログに記録し、OurExceptionでマスクしてから再スローする必要があります。

これは合理的なアプローチですか?もしあれば、より良い選択肢は何ですか?

編集:スタックトレースはリリースモードでは意味のある結果を生成しないと言われました。一般的な例外をキャッチしてスローすることは問題ないことを提案していますか?

Edit2:ありがとうございます。私はこれに対する私の議論の一部としてあなたの答えを使用しましたが、あなたは十分な経験がなく、実際の状況に対処する方法を知らないと言われました。私はこのように行かなければなりません。

4

13 に答える 13

5

例外処理アプリケーションブロックを調べることもできます。

私はいくつかのプロジェクトでそれを使用しました、そしてそれは非常に役に立ちます。特に、後で例外処理の仕組みやキャプチャする情報を変更したい場合。

于 2008-12-23T17:59:30.327 に答える
3

スタック トレースを使用することは、どの識別子よりもはるかに直感的だと思います。

カスタム例外に関しては、なぜこれをしないのですか?

try
{
DoSth();
}
catch(Exception ex)
{
Util.Log(ex.Message, ex.StackTrace);
if(ex is OurException) throw ex;
else throw new OurException(ex); // use the original exception as the InnerException
}

また、処理後に例外を再スローする理由がわかりません。その理由を説明していただけますか?

@Ali A - 非常に有効なポイントなので、言い換えさせてください - ここで例外の処理を終了するのではなく、例外を再スローするのはなぜですか?

編集:

再スローする代わりに、これを行ってみませんか?

try
{
DoSth();
}
catch(Exception ex)
{
Util.HandleException(ex);
}

Util.HandleException:

public static void HandleException(ex)
{
Util.Log(ex); // Util.Log should log the message and stack trace of the passed exception as well as any InnerExceptions - remember, than can be several nested InnerExceptions.

// Any additional handling logic, such as exiting the application, or showing the user an error message (or redirecting in a web app)
}

そうすれば、すべての例外が 1 回だけログに記録されることがわかり、追加の大混乱を引き起こすために例外を野放しにすることはありません。

于 2008-12-23T17:57:33.483 に答える
2

持っているのOurExceptionはちょっと変です。通常、特殊なキャッチブロックが必要で、最後のブロック、ジェネリックをキャッチするブロックExceptionは、ロギングを行う場所です。

try 
{
    DoSomething();
}
catch (DivideByZeroException)
{
    // handle it here, maybe rethrow it, whatever
}
// more catch blocks
catch (Exception)
{
    // oops, this is unexpected, so lets log it
}

しかし、あなたのやっていることはうまくいくでしょう。私はそう1242すべきだと信じています。代わりに使用できるメソッド、ファイル名、および行番号を出力するメソッドは次のとおりです。自分で試したことはありませんが、見た目は良さそうです。

    [Conditional("DEBUG")]
    public static void DebugPrintTrace()
    {
        StackTrace st = new StackTrace(true);
        StackFrame sf = st.GetFrame(1); // this gets the caller's frame, not this one
        Console.WriteLine("Trace "
            + sf.GetMethod().Name + " "
            + sf.GetFileName() + ":"
            + sf.GetFileLineNumber() + "\n");
    } 
于 2008-12-23T18:12:30.300 に答える
1

例外には、修復可能な例外と致命的な例外の2種類があります。一部のオブジェクトが修復可能な例外をスローした場合、これはエラーが発生したことを意味しますが、オブジェクトは破損しておらず、再度使用できます。一部のオブジェクトが致命的な例外をスローした場合、これはオブジェクトの状態が破損していることを意味し、オブジェクトを使用しようとすると新しいエラーが発生します。

更新:すべての例外は、できるだけ早く、エラーソースにできるだけ近い形で処理される可能性があります。たとえば、コレクションに格納されているオブジェクトが致命的な例外をスローした場合、例外ハンドラはこのオブジェクトをコレクションから削除して削除するだけで、オブジェクトのコレクション全体ではありません。

于 2008-12-23T18:03:55.047 に答える
1

私が理解していることから、例外の目的は予期しないエラーを伝播することです。それをスローするメソッドの近くでそれをキャッチすると、それを処理する方法のコンテキストに深く入ります。

あなたの例は、予期しないエラーをキャッチし、それをチェーンに再スローすることです。これは例外を処理するのではなく、独自のものにラップします。

しかし、あなたのラッピングは例外にそれ以上の価値を追加しているようには見えませんが、物事を混乱させる可能性さえあります.

極端な例:

void a() {
  try {
    c();
  } catch(MyException1 ex) {
    throw;
  } catch(Exception ex) {
    log(ex);
    throw new MyException1(ex);
  }
}

void b() {
  try {
    a();
  } catch(MyException2 ex) {
    throw;
  } catch(Exception ex) {
    log(ex);
    throw new MyException2(ex);
  }
}

前の例で、元の例外が 2 回ログに記録されていることに注意してください。そして、それは 2 つの例外に包まれています。同じ例外を数回ログに記録すると、トレースが難しくなります (ログ ファイルがかなり大きくなるため)。

もちろん、これは極端な例かもしれませんが、アプリケーション全体で 1 種類の例外しか使用されていないとは信じがたいと思います。発生する可能性のあるさまざまな種類のエラーのすべてを十分に説明しているわけではありません。

個人的には、例外を処理する catch ブロックでのみ例外をログに記録することを好みます。それ以外の場所では、重複したログが作成される可能性があります。

于 2008-12-24T14:58:47.167 に答える
0

これは悪いパターンだと思います。例外でコールスタック全体に関する情報をすぐに利用できるため、ログに記録して再スローすることで例外を疑似処理する必要はありません。問題について本当に何かできる場所でのみ例外をキャッチします。

于 2008-12-23T18:28:45.637 に答える
0

スタックトレースのログは、ハードコードされた数値よりもはるかに優れています。この数字は、これをどのルーチンと呼んでいるのかについては何も教えてくれません。

また、その数は管理するのが面倒であり、エラーが発生しやすくなります。

編集:スタックトレースがリリースモードで常に意味のある結果を生成するとは限らないことは事実ですが、このハードコードされた数値スキームについても同じことが言えると思います!:-)

使用している言語で、コンパイラーはマクロに現在のファイル名と行番号を提供しますか?それは、自分で一意の番号を転がそうとするよりも良いでしょう。そして、それを自動的に行うことができない場合は、手動で行うか、番号の中央割り当てを必要としない一意性を保証するためのスキームを考え出します!

于 2008-12-23T18:00:25.193 に答える
0

スタックトレースがこれを処理するためのより良い方法であるように私には思えます。誤って番号を再利用するとどうなりますか?

これが良い考えであるかどうかに関しては、これ以上の情報がない限り、私はノーと言う傾向があります。すべてのメソッド呼び出しがtry/catchブロックでラップされている場合、非常にコストがかかります。一般に、例外は2つの陣営に分類されます。合理的に期待して対処できるものと、実際にはバグである(または少なくともうまく予想されていない)ものです。ショットガンアプローチを使用してすべての例外をキャッチすることは、例外を解決するのを助けるよりも、後者を隠すためにもっと役立つかもしれないように私には思えます。これは、トップレベルですべての例外をキャッチし、ログメッセージだけが記録されている場合に特に当てはまります。

于 2008-12-23T18:01:35.300 に答える
0

これがどのように役立つのかわかりません。スタックトレースで例外がどこから来たのかをすでに知ることができ、不必要なレベルの複雑さを追加しています。

于 2008-12-23T18:04:26.747 に答える
0

欠点:

  1. その数はあまり自信を刺激しません、スタックトレースははるかに優れています

  2. カスタム例外を「catch(Exceptionex)」で処理できるのに、なぜ2つのcatchブロックがあるのですか?

于 2008-12-23T18:06:23.310 に答える
0

スロー ラインにハード コードされた番号を使用するのは良い方法ではないと思います。その番号が使用されているかどうかをどのように確認しますか? または、次にスローされるエラー番号はどれですか? たぶん、少なくとも、列挙型にリストすることができます...わかりません。

于 2008-12-23T17:56:32.050 に答える
0

その奇妙な数字を除いて、すべてが正しく見えます。

スタック トレースには、必要な情報が含まれます。

于 2008-12-23T17:57:20.143 に答える
0

私のアプリケーションはリリース モードでビルドされており、例外処理アプリケーション ブロックを使用しているためcatch ex、コードのブロックはありません。EHAB によってキャッチされます。これ自体が、必要なすべての情報を含むログ ファイルに書き込まれます。スタックトレースなど、時間など

これに関する唯一の問題は、誰かが入れた場合です

catch ex
{
    //do stuff
    throw ex;
}

これにより、スタック トレースが消去されます。

于 2008-12-25T15:15:34.540 に答える