[.NET] 例外を Throw しなおすときは、 例外を付けてはいけない ( その3 )
Visual Studio のコード分析で警告される CA2200 "Rethrow to preserve stack details" についての、 最終回です。 ( その2 は、 こちら )
◆ 呼び出す側のメソッド・その3 ( Catch して Throw するだけ )
前回、 Catch して Throw ex と書くと、 スタックトレースがリセットされてしまい、 実際に例外を出したコードが分からなくなってしまうことを示しました。
それでは実際に、 前回のコードの Throw ex の行を Throw に直しただけのものを見てみましょう。
Public Class Class3
Public Shared Sub Method1()
Try
Dim x As Integer
Dim y As Integer
Dim result As Integer
x = 10
result = Module2.Calc1(x, y) '10行目
Catch ex As Exception
Throw '15行目 ( without exception expression )
Finally
Console.WriteLine("* The Finally phrase was excuted in Class3")
End Try
End Sub
End Class
スタックトレースには、 Throw しなおした行と、 問題の Module2 の 5行目が報告されています。
* The Finally phrase was excuted in Class3
OverflowException occured in Class3:
at ThrowVsThrowEx.Module2.Calc1(Int32 x, Int32 y) in E:\sample\ThrowVsThrowEx\ThrowVsThrowEx\Module2.vb:line 5
at ThrowVsThrowEx.Class3.Method1() in E:\sample\ThrowVsThrowEx\ThrowVsThrowEx\Class3.vb:line 15
at ThrowVsThrowEx.Module1.Main() in E:\sample\ThrowVsThrowEx\ThrowVsThrowEx\Module1.vb:line 23
残念ながら Module2.Calc1() を呼び出している 10行目は報告されていませんが、 Try 句の中で Module2.Calc1() を何度も呼び出していない限りは、 すぐに特定できるでしょう。
◆ 呼び出す側のメソッド・その4 ( Catch しない )
ところで、 以上の例 2. と 3. では、 すべての例外を Catch しておきながら何もせず、 ただリスローしています。 このような Catch 句は必要でしょうか? Catch しないと、 Finally 句が実行されないのでしょうか?
Public Class Class4
Public Shared Sub Method1()
Try
Dim x As Integer
Dim y As Integer
Dim result As Integer
x = 10
result = Module2.Calc1(x, y) '10行目
' ( Catch 句は削除 )
Finally
Console.WriteLine("* The Finally phrase was excuted in Class4")
End Try
End Sub
End Class
メイン関数からの出力は、 次のようになります。
* The Finally phrase was excuted in Class4
OverflowException occured in Class3:
at ThrowVsThrowEx.Module2.Calc1(Int32 x, Int32 y) in E:\sample\ThrowVsThrowEx\ThrowVsThrowEx\Module2.vb:line 5
at ThrowVsThrowEx.Class4.Method1() in E:\sample\ThrowVsThrowEx\ThrowVsThrowEx\Class4.vb:line 10
at ThrowVsThrowEx.Module1.Main() in E:\sample\ThrowVsThrowEx\ThrowVsThrowEx\Module1.vb:line 33
最初に示した Try ~ Catch 無しのときと同じように、 問題の Module2 の 5行目と、 呼び出している Class4 の 10行目が、 きちんと報告されています。 また、 Finally 句も実行されていることが分かります。
◆ まとめ
上記の他に、 Catch してからアプリケーション独自の例外オブジェクトを生成して Throw する場合には、 その InnerException に元の例外オブジェクトを入れておくべきです。 ( InnerException の StackTrace を見れば、 本来の例外発生箇所が分かる。 )
以上をまとめると、 Try ~ Catch を使うときのルールは、 次のようになるでしょう。
1. 必要もないのに Try ~ Catch するな !
Catch して何か処理を行う必要があるとき、 または、 Finally 句での処理が必要な時に限って、 Try ~ Catch を使用する。 不要な Try ~ Catch は、 デバッグを困難にするだけ。
2. rethrow するときは、 例外オブジェクトを付けるな !
例外オブジェクトを付けて Throw ex などとすると、 デバッグが困難になる。
ただし、 新しく例外オブジェクトを生成したときは、 InnerException に元の例外オブジェクトを入れて Throw すること。
3. Finally が欲しいだけなら、 Catch 句は不要
※ 以上のソースコード ( VB.NET 2005 )
「ThrowVsThrowEx.zip」 をダウンロード ( 5,410 Bytes )
| 固定リンク
「プログラミング」カテゴリの記事
- 【.NET / Win8.1 ストアアプリ】 HttpClient で TLS 1.1 / 1.2 に対応するには(2018.06.17)
- 【VS2017 15.7pv2】 XAML のランタイム ツールに 「ヒートマップ」 が増えた(2018.03.28)
- 【.NET Core】 プロジェクトを作ると 「project.assets.json が見つかりません」 エラー(2018.02.10)
- 【#UWP】 ビットマップの表示色を変える (Win2D.uwp 経由で Direct2D を使う)(2017.08.23)
- 【#UWP】 CompactOverlay モード: Picture in Picture というか、「最前面に表示」するウィンドウを作る(2017.08.16)
この記事へのコメントは終了しました。
コメント