« [.NET] 例外を Throw しなおすときは、 例外を付けてはいけない ( その2 ) | トップページ | [ゲゲゲの鬼太郎 第50話] こりゃ墓場ネタかも »

2008年3月22日 (土)

[.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] 例外を Throw しなおすときは、 例外を付けてはいけない ( その2 ) | トップページ | [ゲゲゲの鬼太郎 第50話] こりゃ墓場ネタかも »

プログラミング」カテゴリの記事

コメント

この記事へのコメントは終了しました。

トラックバック


この記事へのトラックバック一覧です: [.NET] 例外を Throw しなおすときは、 例外を付けてはいけない ( その3 ):

« [.NET] 例外を Throw しなおすときは、 例外を付けてはいけない ( その2 ) | トップページ | [ゲゲゲの鬼太郎 第50話] こりゃ墓場ネタかも »