連載
プロフェッショナルVB.NETプログラミング
第15回 高度な例外処理
(株)ピーデー
川俣 晶
2002/08/31
|
|
例外の再発生
前回の「構造化例外処理と非構造化例外処理の混用」にあるサンプル・プログラム5の11行目で、Throw文を使用していた。これは、そのサンプル・プログラムでは実行されない部分で、形式的に入れておいただけの文である。しかし、もし実行されたら、どんな効能をもたらすのだろうか?
まず、On Error Goto文もTry文もない状態でエラーが発生するケースを見てみよう。
1: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
2: Dim a As Integer = 1, b As Integer = 0
3: Trace.WriteLine(a \ b)
4: End Sub
|
|
On Error Goto文もTry文も使用していないVB.NETのサンプル・プログラム9 |
これを実行すると以下のようになる。
|
サンプル・プログラム9の実行結果 |
では例外処理の中で、Throw文を実行するとどうなるだろうか。以下は実際に例外処理の中でThrow文が実行されるようにした例である。
1: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
2: Dim a As Integer = 1, b As Integer = 0
3: Try
4: Trace.WriteLine(a \ b)
5: Catch ex As Exception
6: If TypeOf ex Is DivideByZeroException Then
7: Throw
8: End If
9: Trace.WriteLine(ex.Message)
10: End Try
11: End Sub
|
|
例外処理の中でThrow文が実行されるようにしたVB.NETのサンプル・プログラム10 |
これを実行すると以下のようになる。
|
サンプル・プログラム10の実行結果 |
見てのとおり、例外として0除算をキャッチしたはずなのに、まるでそれがなかったかのように同じエラーメッセージが表示されている。Throw文は、例外処理の中で使用されると、例外処理を中止して、そこでもう1度同じ例外を発生させる効能を持つ。もちろん、その時点で発生した例外は、Try文とCatch文の中間で起きているわけではないので、再び同じCatch文でキャッチされることはない。
しかし、例外がネストしている場合、外側のCatch文がこの例外を捕まえることはできる。以下はそのことを示したサンプル・ソースである。
1: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
2: Dim a As Integer = 1, b As Integer = 0
3: Try
4: Try
5: Trace.WriteLine(a \ b)
6: Catch ex As Exception
7: If TypeOf ex Is DivideByZeroException Then
8: Throw
9: End If
10: Trace.WriteLine(ex.Message)
11: End Try
12: Catch ex As DivideByZeroException
13: Trace.WriteLine("0除算をキャッチしました")
14: End Try
15: End Sub
|
|
Throw文による例外をCatch文で捕まえているVB.NETのサンプル・プログラム11 |
これを実行すると以下のようになる。
つまり、8行目で再発生させられた例外は、もはや6行目のCatch文にキャッチされることはないが、その外側の例外ブロック、12行目のCatch文にはキャッチされるということである。
この機能は、実際の例外処理を、よりネストの外側の例外ブロックに任せたいときに有益である。
ユーザーが自ら発生させる例外
例外は、何かのエラーが起こった場合に限らず、自発的にいつでも発生させることができる。VB 6では、Error文や、ErrオブジェクトのRaiseメソッドでエラーを自発的に発生させることができた。以下はError文を使用した例を示したものである。
1: Private Sub Form_Load()
2: Error 11
3: End Sub
|
|
Error文によりエラーを自発的に発生させるVB 6のサンプル・プログラム12 |
これを実行すると以下のようになる。
|
サンプル・プログラム12の実行結果 |
以下はRaiseメソッドを使用した例を示したものである。
1: Private Sub Form_Load()
2: Err.Raise 11
3: End Sub
|
|
Raiseメソッドによりエラーを自発的に発生させるVB 6のサンプル・プログラム13 |
これを実行すると以下のようになる。
|
サンプル・プログラム13の実行結果 |
さて、これと同じように、自発的に例外を発生させるVB.NETのサンプル・プログラムを以下に示す。
1: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
2: Throw New DivideByZeroException()
3: End Sub
|
|
Throw文により自発的に例外を発生させるVB.NETのサンプル・プログラム14 |
これを実行すると以下のようになる。
|
サンプル・プログラム14の実行結果 |
すでに説明したThrow文が再登場したが、今度は引数付きである。引数には例外オブジェクトを指定する。通常は、例外を発生させるときに新しい例外オブジェクトを作成するので、Throw文にはNewキーワードが続くことが多い。そして、発生させたい例外のクラス名を記述する。
ここで注意しておく必要があるのは、引数の有無により、Throw文に出番が変わることである。引数なしのThrow文は例外の再発生という役割を持っている関係上、例外処理中でしか使用できない。しかし、引数を明示したThrow文は新規の例外を発生させるので、特に例外処理中という制約はない。
さて、ErrオブジェクトのRaiseメソッドは、いくつもの引数でエラーの詳細を指定できるが、基本的に例外オブジェクトはRaiseメソッドほど多くの引数を持っていない。しかし、例外はクラスによって指定される関係上、クラスの定義次第でいくらでも引数が増える可能性がある。例えば、FileNotFoundExceptionクラス(ファイルが見付からない例外)のコンストラクタにはファイル名を指定する引数が存在する。
どの例外でも共通に使用できるのは、詳しい説明を示す文字列を付加する機能である。以下はそれを利用した例である。
1: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
2: Throw New DivideByZeroException("Throw文により発生した例外です。")
3: End Sub
|
|
例外の説明を示す文字列を利用したVB.NETのサンプル・プログラム15 |
これを実行すると以下のようになる。
|
サンプル・プログラム15の実行結果 |
見てのとおり、単に例外を発生させるだけでなく、説明のための文字列を付加することができている。
次回予告
次回も例外処理について残された解説を続けることを予定している。例外処理は、スマートでエラーに強いプログラムを記述するために重要な機能である。がんばってマスターしよう。
Insider.NET 記事ランキング
本日
月間