.NETでは、キャッチが再スローするだけのtry / catchに利点がありますか[複製]
質問
可能な重複:
C#で例外をキャッチして再スローする理由
時々、次のようなC#コードに遭遇します。
try
{
// Some stuff
}
catch (Exception e)
{
throw e;
}
例外メッセージをログに記録してから再スローするようなことができることを理解しています。例外を再スローするだけのキャッチについて話しています。これには意味がありません。 3つの質問があります:
1)これには利点がありますか
2)これによりコードが遅くなりますか
3)catchブロックが次のようであれば、違いが生じますか
catch (Exception)
{
throw;
}
解決
これにより、同じ例外 exact が再スローされます:
catch (Exception)
{
throw;
}
これにより、元のスタックトレースなしで例外が再スローされます。
catch (Exception e)
{
throw e;
}
例外を記録するか、例外を再スローする前に他のことを行うことができるため、 throw;
の正当な理由がしばしばあります。貴重なスタックトレース情報を消去するため、 throw e;
の理由はわかりません。
他のヒント
キャッチで他に何もしない場合...しかし、これは、キャッチや他の種類の例外処理など、キャッチで再スローする前に他のことを行うためによく使用されます。
このテクニックを使用して、デバッグ時にブレークポイントをスローできるようにします。終わったら削除することもあります...
主な違いは、例外のスタックトレースが変更され、最初の例のtry-catchの場所から発生したことを示すことです。
2番目の例は、スタックトレースを維持します。
利点はありますか
一般的に言えばいいえ。このパターンは、スタックトレースを新しいスローのポイントにリセットするだけです。これにより、開発者が問題の原因を突き止めるのが難しくなります
コードの速度を遅くしますか
まったく?おそらく。測定可能な差で速度を落としますか?いいえ。
catchブロックが次のようであれば、違いが生じますか?
はい、そのキャッチは本質的に完全に冗長です。元のスタックトレースを維持し、アプリケーションに目に見える影響を与えない例外を再スローします。
1-利点がまったくありません。例外を処理していない場合は、try / catchをオフのままにします。この例のもう1つの問題は、実際の例外をスローするのではなく、新しい例外をスローすることです。
2-はい-しかし、これが繰り返しコードの大きなループ内にある場合を除き、おそらく違いに気付かないでしょう。
3-はい。最初の例では、呼び出しスタックをいじっています。この例では、新しい例外をスローするのではなく、例外をバブリングしてスタックをそのまま保持します。
本当に他に何もしていない場合、私が見つけた利点は1つしかありません。 throw
行にブレークポイントを設定できます。 (例外タイプがスローされるたびに破壊するのではなく)非常に具体的になります。
しかし、デバッグ中にそれを行うだけで、その後コードを元に戻します。
違いを示す簡単なテストを作成しました。テストコードは次のとおりです。
try
{
var broken = int.Parse("null");
}
catch (Exception ex1)
{
System.Diagnostics.Trace.WriteLine(ex1.ToString());
}
try
{
try
{
var broken = int.Parse("null");
}
catch (Exception)
{
throw;
}
}
catch (Exception ex2)
{
System.Diagnostics.Trace.WriteLine(ex2.ToString());
}
try
{
try
{
var broken = int.Parse("null");
}
catch (Exception ex3)
{
throw ex3;
}
}
catch (Exception ex4)
{
System.Diagnostics.Trace.WriteLine(ex4.ToString());
}
これを実行すると、次の出力が得られます。
A first chance exception of type 'System.FormatException' occurred in mscorlib.dll
System.FormatException: Input string was not in a correct format.
at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
at System.Int32.Parse(String s)
at QuickTests.Program.Main(String[] args) in C:\Projects\Test\QuickTests\Program.cs:line 18
A first chance exception of type 'System.FormatException' occurred in mscorlib.dll
A first chance exception of type 'System.FormatException' occurred in QuickTests.exe
System.FormatException: Input string was not in a correct format.
at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
at System.Int32.Parse(String s)
at QuickTests.Program.Main(String[] args) in C:\Projects\Test\QuickTests\Program.cs:line 33
A first chance exception of type 'System.FormatException' occurred in mscorlib.dll
A first chance exception of type 'System.FormatException' occurred in QuickTests.exe
System.FormatException: Input string was not in a correct format.
at QuickTests.Program.Main(String[] args) in C:\Projects\Test\QuickTests\Program.cs:line 49
最初の2つの例外は同じように機能します。したがって、「投げる」"スタックを上に移動する例外までは何も変更しません。ただし、「ex3を投げる」」報告された例外が異なり、例外のスタックトレースが変更されます。
これは、ロギングに適しています。また、再スローで引数を省略すると、eのスタックトレースは変更されません。
特定のタイプを介して許可したい場合があります。 FooException以外のすべての特別な処理を次に示します。
try
{
// ...
}
catch (FooException)
{
throw;
}
catch (Exception ex)
{
// handle differently, like wrap with a FooException
throw new FooException("I pitty the Foo.", ex);
}
もちろん。
ほとんどの場合、例外をスローする前にログに記録し、おそらくメソッドからいくつかの変数値を記録します。
ただキャッチして投げるだけでは、それほど多くは得られません。
そのように、いいえ。ただし、これを行うこともできます。
catch (Exception ex)
{
LogException(ex);
throw;
}
LogException()は、erm、例外をログに記録するか、アラートなどをメールで送信するカスタムクラスです。
重要なのは、例外のTYPEが1つだけスローされるようにすることです。それはかなり悪いアンチパターンIMHOです
e.g。
try
{
throw XYZ();
}
catch(Exception e)
{
throw e;
}