SSブログ

[.NET]例外の再スロー(Throwの引数の有無) [Programming .NET Tips]

[ポイント]
・.NET系言語(C#、VB.NET)のプログラムコードで、
 以下のような構文を見かけることがあります。
  Try 
    Dim x As Integer = func2(a) 
    Return x 
  Catch ex As Exception 
    '何らかの例外後の後処理をして、再スロー 
    '(例外後の処理は割愛)... 
    Throw ex    '←ここに注目 
  End Try
[VB.NET]例外の再スロー[Throwの引数がある場合]
 Tryステートメント内で発生した例外をCatchして、
 再度スローする処理で、「Throw ex」と書く人が結構多いようですが、
 実はこのような書き方をすると、
 ここでCatchする以前のトレース情報が失われてしまうのです。

 トレース情報を保持しつつ再スローするには、
 以下の様に、「Throw ex」ではなく「Throw 」と記述します。
  Try 
      Dim x As Integer = func2(a) 
      Return x 
  Catch ex As Exception 
      '何らかの例外後の後処理をして、再スロー 
      '(例外後の処理は割愛)... 
      Throw    '←exは省略します。 
  End Try 
[VB.NET]例外の再スロー[Throwの引数がない場合]

 なぜか書籍やMSDNにも、前者の書き方でサンプルを紹介している為、
 知らない人が多いようです。
 (Throwステートメントとは直接関係ないサンプルだから、
  あまり重要視していないのだと思いますが…)
[参考文献]
「C#クックブック 第3版」
 「レシピ4.1 キャッチした例外を再スローするタイミングを把握する」で、
 Throwステートメントの引数の有無の違いを明確に説明しています。
 「Throw」(引数なし)の記述を推奨しています。
「プログラミングC#―C#2.0/.NET2.0/Visual Studio2005対応」
 「11.4 例外の再スロー」で、
 理由の説明はないが、「Throw」(引数なし)の記述を推奨しています。

[検証]
 Throwステートメントの仕様について、
 2つのパターンの検証プログラムを実行して、結果を比較してみた。
パターン1
 Throwステートメントに引数がある場合、
 Button1_Click()→Method1()→Method2()→Method3()→Method4()と
 メソッドを呼び、最下層のMethod4()で
 ゼロ除算の例外(System.DevideByZeroException)を意図的に発生させる。
 各々のメソッドのCatch句では、「Throw ex」(引数あり)で例外を再Throwする。
 最上位メソッドにて、例外の内容(ToString()した結果)を表示する。
パターン2
 Throwステートメントに引数がない場合、
 Button1_Click()→Method1()→Method2()→Method3()→Method4()と
 メソッドを呼び、最下層のMethod4()で
 ゼロ除算の例外(System.DevideByZeroException)を意図的に発生させる。
 各々のメソッドのCatch句では、「Throw 」(引数なし)で例外を再Throwする。
 最上位メソッドにて、例外の内容(ToString()した結果)を表示する。

・パターン1(Throwステートメントに引数がある場合)
Private Sub Button1_Click( _
    ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles Button1.Click
    Dim num As Integer

    Try
        num = Method1(1, 0)
    Catch ex As Exception
        MessageBox.Show( _
            ex.ToString(), _
            "例外[Throwの引数がある場合]")
    End Try
End Sub

Private Function Method1( _
    ByVal a As Integer, _
    ByVal b As IntegerAs Integer

    Try
        Return Method2(a, b)
    Catch ex As Exception
        Throw ex
    End Try
End Function

Private Function Method2( _
    ByVal a As Integer, _
    ByVal b As IntegerAs Integer

    Try
        Return Method3(a, b)
    Catch ex As Exception
        Throw ex
    End Try
End Function

Private Function Method3( _
    ByVal a As Integer, _
    ByVal b As IntegerAs Integer

    Try
        Return Method4(a, b)
    Catch ex As Exception
        Throw ex
    End Try
End Function

Private Function Method4( _
    ByVal a As Integer, _
    ByVal b As IntegerAs Integer

    Try
        'b=0の時に例外が発生する。
        Return a \ b
    Catch ex As Exception
        Throw ex
    End Try
End Function
[VB.NET]例外[Throwの引数がある場合]
・パターン1の実行結果(Throwステートメント[引数あり])
 Throwの引数を指定した場合は、
 保持されているトレース情報は、Method1、Button1_Clickのみで、
 Method2、Method3、Method4は保持されていないことがわかります。
 引数指定での再スローでは、それより前のトレース情報を保持しない為です。
 この例では、
  Method3で再スローする時に、Method4以降のトレース情報を保持しない、
  Method2で再スローする時に、Method3以降のトレース情報を保持しない、
  Method1で再スローする時に、Method2以降のトレース情報を保持しない為、
 図のような結果になります。
例外[Throwの引数がある場合]

・パターン2(Throwステートメント[引数なし])
Private Sub Button1_Click( _
    ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles Button1.Click
    Dim num As Integer

    Try
        num = Method1(1, 0)
    Catch ex As Exception
        MessageBox.Show( _
            ex.ToString(), _
            "例外[Throwの引数がない場合]")
    End Try
End Sub

Private Function Method1( _
    ByVal a As Integer, _
    ByVal b As IntegerAs Integer

    Try
        Return Method2(a, b)
    Catch ex As Exception
        Throw
    End Try
End Function

Private Function Method2( _
    ByVal a As Integer, _
    ByVal b As IntegerAs Integer

    Try
        Return Method3(a, b)
    Catch ex As Exception
        Throw
    End Try
End Function

Private Function Method3( _
    ByVal a As Integer, _
    ByVal b As IntegerAs Integer

    Try
        Return Method4(a, b)
    Catch ex As Exception
        Throw
    End Try
End Function

Private Function Method4( _
    ByVal a As Integer, _
    ByVal b As IntegerAs Integer

    Try
        'b=0の時に例外が発生する。
        Return a \ b
    Catch ex As Exception
        Throw
    End Try
End Function
[VB.NET]例外[Throwの引数がない場合]
・パターン2の実行結果(Throwステートメント[引数なし])
 Throwの引数を指定しない場合は、
 関連するトレース情報(Method1、Method2、Method3、Method4、Button1_Click)を
 全て保持していることがわかります。
例外[Throwの引数がない場合]

nice!(0)  コメント(0)  トラックバック(0) 
共通テーマ:パソコン・インターネット

nice! 0

コメント 0

コメントを書く

お名前:[必須]
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。