9

私は次のタイプのコードに何度も出くわしましたが、これが (パフォーマンスの観点から) 良い習慣であるかどうか疑問に思います:

try
{
    ... // some code
}
catch (Exception ex)
{
    ... // Do something
    throw new CustomException(ex);
}

基本的に、コーダーが行っていることは、例外をカスタム例外に含めて、それを再度スローすることです。

これは、次の 2 つとパフォーマンスがどのように異なりますか。

try
{
    ... // some code
}
catch (Exception ex)
{
    .. // Do something
    throw ex;
}

また

try
{
    ... // some code
}
catch (Exception ex)
{
    .. // Do something
    throw;
}

機能的またはコーディングのベスト プラクティスの議論はさておき、3 つのアプローチの間にパフォーマンスの違いはありますか?

4

8 に答える 8

11

@ブラッド・タテロウ

最初のケースでは例外が失われておらず、コンストラクターに渡されています。残りの部分については同意しますが、スタック トレースが失われるため、2 番目のアプローチは非常に悪い考えです。私が .NET を扱っていたとき、他のプログラマーがまさにそれを行った多くのケースに出くわしました。例外の真の原因を確認する必要があるとき、それが巨大な try ブロックから再スローされていることを発見するだけで、私は際限なくイライラしました。問題の原因がどこにあるのか、今ではわかりません。

また、パフォーマンスについて心配する必要はないというブラッドのコメントにも同意します。この種のマイクロ最適化は恐ろしいアイデアです。長時間実行されている for ループのすべての反復で例外をスローすることについて話している場合を除き、例外の使用によってパフォーマンスの問題が発生することはほとんどありません。

パフォーマンスを最適化する必要があることを示すメトリクスがある場合は、常にパフォーマンスを最適化し、原因であることが証明されているスポットを見つけます。

何かをナノ秒速く実行するよりも、簡単なデバッグ機能 (IE ではスタック トレースを非表示にしない) を備えた読み取り可能なコードを使用する方がはるかに優れています。

例外をカスタム例外にラップすることに関する最後の注意...これは、特に UI を扱う場合に、非常に便利な構造になる可能性があります。すべての既知の合理的な例外ケースをいくつかの基本カスタム例外 (またはその基本例外から拡張されたもの) にラップすると、UI はこの基本例外をキャッチできます。キャッチされた場合、例外はユーザーに情報を表示する手段、たとえば ReadableMessage プロパティなどを提供する必要があります。したがって、UI で例外が見逃される場合は、修正が必要なバグが原因であり、例外がキャッチされた場合は、UI で適切に処理できる既知のエラー状態です。

于 2008-08-09T21:17:35.057 に答える
2

してはいけないこと:

try
{
    // some code
}
catch (Exception ex) { throw ex; }

これにより、スタック トレースが失われるためです。

代わりに次のようにします。

try
{
    // some code
}
catch (Exception ex) { throw; }

スローするだけで十分です。新しいカスタム例外の内部例外にしたい場合は、例外変数を渡すだけです。

于 2008-08-16T14:24:37.277 に答える
2

David のように、2 番目と 3 番目の方がパフォーマンスが良いと思います。しかし、3 つのうちのどれかが、それについて心配するのに時間を費やすほどパフォーマンスが悪いでしょうか? 心配するパフォーマンスよりも大きな問題があると思います。

元のスタック トレースが失われないように、FxCop は常に 2 番目のアプローチよりも 3 番目のアプローチを推奨します。

編集: 単純に間違っていたものを削除し、Mike が親切に指摘してくれました。

于 2008-08-09T20:58:21.243 に答える
2

明らかに、新しいオブジェクト (新しい例外) を作成するペナルティが発生するため、プログラムに追加するコードのすべての行で行うのとまったく同じように、例外のより適切な分類が余分な作業に見合うかどうかを判断する必要があります。

その決定を下すためのアドバイスとして、新しいオブジェクトが例外に関する追加情報を持っていない場合は、新しい例外の作成を忘れることができます。

ただし、他の状況では、クラスのユーザーにとって例外の階層があると非常に便利です。Facade パターンを実装しているとします。これまでに検討したシナリオはどちらも適切ではありません。

  1. (おそらく)貴重な情報を失っているため、すべての例外を Exception オブジェクトとして発生させるのは良くありません
  2. キャッチしたあらゆる種類のオブジェクトを上げるのも良くありません。そうすると、ファサードの作成に失敗するからです

この架空のケースでは、例外クラスの階層を作成して、システムの内部の複雑さからユーザーを抽象化し、生成された例外の種類について何かを知ることができるようにすることをお勧めします。

補足として:

個人的には、例外 (Exception クラスから派生したクラスの階層) を使用してロジックを実装するのは嫌いです。場合のように:

try {
        // something that will raise an exception almost half the time
} catch( InsufficientFunds e) {
        // Inform the customer is broke
} catch( UnknownAccount e ) {
        // Ask for a new account number
}
于 2008-08-09T21:01:14.187 に答える
1

他の人が述べているように、既存のオブジェクトを再スローしているだけなので、最高のパフォーマンスは一番下のものから得られます。スタックを失うため、中央のものは最も正確ではありません。

コード内の特定の依存関係を分離したい場合、私は個人的にカスタム例外を使用します。たとえば、XML ファイルからデータをロードするメソッドがあります。これは、さまざまな点でうまくいかない可能性があります。

ディスクからの読み取りに失敗する (FileIOException)、ユーザーが許可されていない場所からアクセスしようとする (SecurityException)、ファイルが破損している (XmlParseException)、データが間違った形式である (DeserialisationException) 可能性があります。

この場合、呼び出し元のクラスがこれらすべてを理解しやすくなります。これらすべての例外は単一のカスタム例外 (FileOperationException) を再スローするため、呼び出し元は System.IO または System.Xml への参照を必要とせず、それでも参照できます。列挙型と重要な情報を介して発生したエラーにアクセスします。

述べたように、このようなものをマイクロ最適化しようとしないでください。例外をスローする行為は、ここで発生する最も遅いことです。最善の改善策は、例外をまったく回避することです。

public bool Load(string filepath)
{
  if (File.Exists(filepath)) //Avoid throwing by checking state
  {
    //Wrap anyways in case something changes between check and operation
    try { .... }
    catch (IOException ioFault) { .... }
    catch (OtherException otherFault) { .... }
    return true; //Inform caller of success
  }
  else { return false; } //Inform caller of failure due to state
}
于 2008-08-10T01:03:49.720 に答える
0

待ってください....例外がスローされた場合、なぜパフォーマンスを気にするのですか?通常のアプリケーションフローの一部として例外を使用している場合を除きます(これはベストプラクティスに対してWAYYYYです)。

私は成功に関してのみパフォーマンス要件を見てきましたが、失敗に関しては見たことがありません。

于 2008-09-30T12:56:02.500 に答える
0

最初の例のスローには、新しい CustomException オブジェクトの作成のオーバーヘッドがあります。

2 番目の例の再スローは、タイプ Exception の例外をスローします。

3番目の例の再スローは、「何らかのコード」によってスローされたのと同じタイプの例外をスローします。

したがって、2 番目と 3 番目の例では、使用するリソースが少なくなります。

于 2008-08-09T20:50:35.503 に答える
0

純粋にパフォーマンスの観点からは、3 番目のケースが最もパフォーマンスが高いと思います。他の 2 つは、スタック トレースを抽出して新しいオブジェクトを作成する必要があり、どちらもかなり時間がかかる可能性があります。

これら 3 つのコード ブロックの (外部) 動作は非常に異なるため、それらを比較することは、アイテムを赤黒ツリーに追加するよりもクイック ソートの方が効率的かどうかを尋ねるようなものです。正しいことを選択することほど重要ではありません。

于 2008-08-10T00:47:17.023 に答える