連載
プロフェッショナルVB.NETプログラミング
第16回 例外処理を極める
(株)ピーデー
川俣 晶
2002/09/07
|
|
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個しか存在しないため、新しいエラーが発生すると内容が上書きされるが、構造化例外処理の例外オブジェクトは複数のオブジェクトが存在できるので、このような使い方もできるのである。
Insider.NET 記事ランキング
本日
月間