|
|
連載
改訂版
プロフェッショナルVB.NETプログラミング
Chapter 09 例外処理
株式会社ピーデー
川俣 晶
2004/06/10 |
|
|
構造化例外処理と非構造化例外処理の機能を同時に使うことができるだろうか? 例えば、上記のサンプル・ソースでエラーの種類を判定するために、Errオブジェクトが使えるだろうか? リスト9-9はそれを確認するために記述したサンプル・ソースである。
1: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
2: Dim i As Integer
3: For i = -2 To 2
4: Dim j As Integer
5: Try
6: j = 10 \ i
7: Catch ex As Exception
8: If Err.Number = 11 Then
9: Trace.WriteLine("∞")
10: Else
11: Throw
12: End If
13: End Try
14: Trace.WriteLine(j)
15: Next
16: End Sub
|
|
リスト9-9 構造化例外処理と非構造化例外処理の機能を同時に使用したプログラム
|
これを実行すると以下のようになる。ただし、システムからのメッセージは除いてある。
1: -5
2: -10
3: ∞
4: -10
5: 10
6: 5
|
|
リスト9-10 リスト9-9の実行結果
|
構造化例外処理の中で、非構造化例外処理用のErrオブジェクトを使用してエラー番号を調べているが、確かに判定が実行されている。つまり、例外クラスの名前ではなく、エラー番号によるエラーの種類の判定が実現できている。
しかし、このような方法はあまりお勧めではない。現在はたまたま動いているが、VB.NETの将来バージョンで動作するか分からないし、そもそも、将来的に非構造化例外処理がサポートされなくなる可能性も、決して小さくはない。できるだけ、構造化例外処理だけで記述するように心掛けるほうがよいだろう。
VB 6には、On Error Resume Nextステートメントがある。これは、エラーが発生してもそのまま次のステートメントに動作を進めるというラフな機能を指定する。当然、エラーが起こるとデタラメな動作が続くだけの無意味なプログラムになってしまう。では、On Error Resume Nextステートメントの存在意義は何かというと、エラーが発生する可能性のあるステートメントの実行直後に、Errオブジェクトを参照して、エラーの有無を確認するようなプログラミングスタイルを実現することである。実際にVB 6で、このようなスタイルで記述したソースをリスト9-11に示す。
1: Private Sub Form_Load()
2: On Error Resume Next
3: Dim i As Integer
4: For i = -2 To 2
5: Dim j As Integer
6: j = 10 / i
7: If Err = 11 Then
8: Debug.Print "∞"
9: Err.Clear
10: End If
11: Debug.Print j
12: Next
13: End Sub
|
|
リスト9-11 On Error Resume Nextステートメントを使用したプログラム
|
これを実行すると以下のようになる。
1: -5
2: -10
3: ∞
4: -10
5: 10
6: 5
|
|
リスト9-12 リスト9-11の実行結果
|
こうすると、On Error Gotoを使用する場合より処理が直線的になって、流れを追いやすい。しかし、プログラマーがあらかじめ想定していないエラーが発生した場合には、そのまま処理が続く危険もある。
さて、このソースをできるだけ忠実にVB.NET上に再現したものがリスト9-13である。
1: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
2: On Error Resume Next
3: Dim i As Integer
4: For i = -2 To 2
5: Dim j As Integer
6: j = 10 \ i
7: If Err.Number = 11 Then
8: Trace.WriteLine("∞")
9: Err.Clear()
10: End If
11: Trace.WriteLine(j)
12: Next
13: End Sub
|
|
リスト9-13 リスト9-11をVB.NETで再現したプログラム
|
これを実行すると以下のようになる。ただし、システムからのメッセージは除いてある。
1: -5
2: -10
3: ∞
4: -10
5: 10
6: 5
|
|
リスト9-14 リスト9-13の実行結果
|
見てのとおり、ほとんど変わらないソース・コードが使用できることが分かるだろう。しかし、On Error Resume Nextステートメントは、非構造化例外処理の機能の1つである。では、構造化例外処理を使って、どのように記述すればそれに相当するソース・コードが作成できるだろうか。
結論をいえば、On Error Resume Nextステートメントに相当する機能は、構造化例外処理には含まれていない。これは、すべてのエラー処理を暗黙のうちに決め打ちしてしまうことが危険だから、と解釈すべきだろう。起こり得るエラーに対する対応コードを、すべて明示的にTryステートメントとCatchブロックで表現することは、プログラムの品質を向上させるうえで意味があることである。
1つのTryステートメントに記述できるCatchブロックは、1つに限られない。つまり、1つのTryステートメントで、複数の例外クラスをキャッチすることができる。これを行う実例のサンプル・ソースを示そう。まず、VB 6でファイルを開く際、ファイルが見つからない場合とディレクトリが見つからない場合の処理を記述した例を見てみよう。
1: Private Sub test(ByVal s As String)
2: On Error GoTo errorHandler
3: Open s For Input As #1
4: Close #1
5: Exit Sub
6:
7: errorHandler:
8: If Err = 53 Then
9: Debug.Print "ファイルが見つかりません: " & s
10: ElseIf Err = 76 Then
11: Debug.Print "ディレクトリが見つかりません: " & s
12: Else
13: Err.Raise (Err)
14: End If
15: Exit Sub
16: End Sub
17:
18: Private Sub Form_Load()
19: test "c:\存在しないファイル.txt"
20: test "c:\存在しないディレクトリ\test.txt"
21: End Sub
|
|
リスト9-15 複数のエラーを同時に扱うプログラム
|
これを実行すると以下のようになる。
1: ファイルが見つかりません: c:\存在しないファイル.txt
2: ディレクトリが見つかりません: c:\存在しないディレクトリ\test.txt
|
|
リスト9-16 リスト9-15の実行結果
|
さて、非構造化例外処理を用いれば、VB.NETでこれとほぼ同等のソースを記述できることが予測できるだろう。では、構造化例外処理を使用して書き直した場合、どのような内容になるだろうか。実際に記述してみたのがリスト9-17である。
1: Private Sub test(ByVal s As String)
2: Try
3: FileOpen(1, s, OpenMode.Input)
4: FileClose(1)
5: Catch ex As System.IO.FileNotFoundException
6: Trace.WriteLine("ファイルが見つかりません: " & ex.FileName)
7: Catch ex As System.IO.DirectoryNotFoundException
8: Trace.WriteLine("ディレクトリが見つかりません: " & s)
9: End Try
10: End Sub
11:
12: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
13: test("c:\存在しないファイル.txt")
14: test("c:\存在しないディレクトリ\test.txt")
15: End Sub
|
|
リスト9-17 リスト9-15をTry〜Catchにより書き換えたVB.NETのプログラム
|
これを実行すると以下のようになる。ただし、システムからのメッセージは除いてある。
1: ファイルが見つかりません: c:\存在しないファイル.txt
2: ディレクトリが見つかりません: c:\存在しないディレクトリ\test.txt
|
|
リスト9-18 リスト9-17の実行結果
|
ここで注目すべきことは、1つのTryステートメントに対応するCatchブロックが2つ存在することである。このように、1つのTryステートメントに対応するCatchブロックはいくつでも記述することができる。
さて、主要なテーマではないが、6行目のex.FileNameについても少しだけ説明しよう。System.IO.FileNotFoundExceptionクラスは、見つからなかったファイルのファイル名を保持するFileNameプロパティを持っている。これを参照することで、例外処理の中で、エラー・メッセージを組み立てることが容易になる。このように、例外オブジェクトも種類によって、内容に相違がある場合がある。これは、1種類のErrオブジェクトですべてのエラーを扱う非構造化例外処理に対する長所といえる。
業務アプリInsider 記事ランキング
本日
月間