連載

プロフェッショナルVB.NETプログラミング

第16回 例外処理を極める

(株)ピーデー
川俣 晶
2002/09/07

Page1 Page2 Page3

InnerExceptionについて

 あるエラーが発生した場合、それを別のエラーとして扱いたい場合がある。例えば、ファイルが見付からないときに、それを「ファイルが見付からない」というエラーとして処理するのではなく、何らかのパラメータ・エラーとして扱いたい場合があるだろう。つまりプロシージャに渡すパラメータの値の問題であると捉えたい、というわけだ。そういう場合、1度エラーをトラップしてから、もう1度エラーを発生させるという方法が可能である。実際にVB 6でそれを記述した例を以下に示す。

  1: Private Function GetData(ByVal filename As String)
  2:   On Error GoTo errorHandlerInCalc
  3:   Open "c:\" & filename & ".txt" For Input As #1
  4:   Close 1
  5:   Exit Function
  6:
  7: errorHandlerInCalc:
  8:   If Err.Number <> 53 Then
  9:     Err.Raise Err.Number
 10:   Else
 11:     Err.Raise 1234
 12:   End If
 13: End Function
 14:
 15: Private Sub Form_Load()
 16:   On Error GoTo errorHandlerInMain
 17:   Debug.Print GetData("app_define_data")
 18:   Exit Sub
 19:
 20: errorHandlerInMain:
 21:   If Err.Number <> 1234 Then
 22:     Err.Raise Err.Number
 23:   Else
 24:     MsgBox "内部パラメータエラーです。"
 25:   End If
 26: End Sub
エラー処理の中で、さらにエラーを発生させているVB 6のサンプル・プログラム4

 これを実行すると以下のようになる。

サンプル・プログラム4の実行結果

 このソースはほとんどそのままVB.NETでも動作する。

  1: Private Function GetData(ByVal filename As String)
  2:   On Error GoTo errorHandlerInCalc
  3:   FileOpen(1, "c:\" & filename & ".txt", OpenMode.Input)
  4:   FileClose(1)
  5:   Exit Function
  6:
  7: errorHandlerInCalc:
  8:   If Err.Number <> 53 Then
  9:     Err.Raise(Err.Number)
 10:   Else
 11:     Err.Raise(1234)
 12:   End If
 13: End Function
 14:
 15: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 16:   On Error GoTo errorHandlerInMain
 17:   Trace.WriteLine(GetData("app_define_data"))
 18:   Exit Sub
 19:
 20: errorHandlerInMain:
 21:   If Err.Number <> 1234 Then
 22:     Err.Raise(Err.Number)
 23:   Else
 24:     MsgBox("内部パラメータエラーです。")
 25:   End If
 26: End Sub
サンプル・プログラム4をVB.NETで書き換えたサンプル・プログラム5

 これを実行すると以下のようになる。

サンプル・プログラム5の実行結果

 これを、構造化例外処理を用いて書き直すと、以下のようになる。

  1: Class InternalParameterErrorException
  2:   Inherits Exception
  3:   Public Sub New(ByVal msg As String, ByVal innerException As Exception)
  4:     MyBase.New(msg, innerException)
  5:   End Sub
  6: End Class
  7:
  8: Private Function GetData(ByVal filename As String)
  9:   Try
 10:     FileOpen(1, "c:\" & filename & ".txt", OpenMode.Input)
 11:     FileClose(1)
 12:     Return "ファイルから読み出したつもりのダミーデータ"
 13:   Catch ex As System.IO.FileNotFoundException
 14:     Throw New InternalParameterErrorException("内部パラメータエラーです。", ex)
 15:   End Try
 16: End Function
 17:
 18: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 19:   Try
 20:     Trace.WriteLine(GetData("app_define_data"))
 21:   Catch ex As InternalParameterErrorException
 22:     MsgBox(ex.Message & " (" & ex.InnerException.Message & ")")
 23:   End Try
 24: End Sub
サンプル・プログラム5を、構造化例外処理を用いて記述したVB.NETのサンプル・プログラム6

 これを実行すると以下のようになる。

サンプル・プログラム6の実行結果

 ここで結果を見比べて欲しい。構造化例外処理を使った例では、具体的に見つからなかったファイルのファイル名も表示されている。これは例外オブジェクトのInnerExceptionプロパティを利用することで実現されている。InnerExceptionプロパティは、ある例外を発生させる原因となった別の例外についての情報を保持することができる。つまり、1つの例外に対応する例外オブジェクトは1つに限られることはなく、その例外の原因となった例外に対応するオブジェクトも保持し続けることができる。もちろん、原因の例外オブジェクトにもInnerExceptionプロパティがあるので、保持できる例外の個数は2個に限定されない。

 これに対応するために、3〜5行目のコストラクタは、innerExceptionを引数に持つ形で実装し、4行目でExceptionクラスのコンストラクタにもinnerExceptionの情報を引き渡している。そして、14行目で例外を再発生させる際、引数に原因となる例外オブジェクトを指定する。この情報は21行目でキャッチされるときに引き継がれており、22行目のようにex.InnerExceptionとすることで参照できる。つまり、ex.Messageは例外を説明する文字列を持ち、ex.InnerException.Messageは原因となった例外を説明する文字列を持つ。

 非構造化例外処理で使用されるErrオブジェクトはシステム内に1個しか存在しないため、新しいエラーが発生すると内容が上書きされるが、構造化例外処理の例外オブジェクトは複数のオブジェクトが存在できるので、このような使い方もできるのである。


 INDEX
  連載 プロフェッショナルVB.NETプログラミング
  第16回 例外処理を極める
    1.例外の自作
  2.InnerExceptionについて
    3.Finally文の確実性
 
「プロフェッショナルVB.NETプログラミング」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間