※この記事は【VB6・VB】古いコードのリプレース のシリーズその3です。
#On Errorステートメントとは
VB6時代からあるエラー対処法。
最も簡単な例がこちら
On Error GoTo Err
'処理...
'..
Err:
最初に断っておきますが、これは今でも使えます。
けど少なくとも、今から新しく書くような用法ではないです。
なぜなら、Try-Catchがあるから。
#Try-Catchとは
VBから出来たエラー対処法。
Try
'処理...
'..
Catch ex As Exception
End Try
・On Error Gotoが出来ることは殆どTry-Catchでも出来ます。
・逆にTry-Catchに出来て、On Error Gotoに出来ないことはたくさんあります。
-
Try-Catchにしか出来ないこと
-
Finallyが使える(重要)
-
エラーの詳細情報を出力できる(On ErrorにはErr.Number程度しかない)
-
GoToなんて汚い言葉を使わなくて済む
ということでTry-Catchを使わない理由がないです。
これはもうTry-Catchに置き換えるしかないですね。
#On Error -> Try-Catch 置き換え例
例1 通常の置き換え
例2 Err.Numberがあるとき
例3 Resume Next / Goto 0 がある場合
##例1 通常の置き換え
通常の置き換えはさきほどの例そのままです。
##例2 Err.Numberがあるとき
On Error GoTo Err
'処理...
'..
Err:
If Err.Number = 53 Then
'特別なエラー処理..
End If
'普通のエラー処理..
ErrObjectの.Numberの値によって個別で何か処理をやっている場合。
この場合、そのエラーが一体何のエラーなのか調べて、そのエラーと対応するExceptionを探さないといけません。
NumberとExceptionは1:1で対応しているわけではありません。
内容を見て実際に動かして確認するしかありません。
よくErr.Numberで特殊対応しているのを見るのは↓あたりでしょうか。
.Number | .Description |
---|---|
5 | プロシージャの呼び出し、または引数が不正です。 |
9 | インデックスが有効範囲にありません。 |
11 | 0 で除算しました。 |
13 | 型が一致しません。 |
53 | ファイルが見つかりません。または存在しないファイルを参照しています。 |
75 | パス名が無効です。 |
76 | パスが見つかりません。 |
321 | 不正なファイル形式です。 |
31036 | ファイルへの書き込み中にエラーが発生しました。 |
31037 | ファイルの読み込み中にエラーが発生しました。 |
特にVB6はファイルとのやりとりがお粗末なものしかなかったので、ファイル関係のエラートラップが多いかと思います。
たとえば上のErr.Number=53「ファイルが見つかりません。または存在しないファイルを参照しています。」
の場合は、以下のような変更でいいでしょう。
(IOExceptionもあったほうが安全かも)
Try
'処理..
Catch ex As System.IO.FileNotFoundException
'特別なエラー処理..
Catch ex As Exception
'普通のエラー処理..
End Try
##例3 Resume Next / Goto 0 がある場合
Resume Nextは出たエラーを無視してそのまま次の処理へ進むため、本当に現在の設計思想からしたらメチャクチャな動きをします。
無視する範囲の終わりにOn Error Goto 0とつけるのが基本的な使用方法です。
例えば、こういうコードが書けます。
'4回割り算したいと決まっているとする
Dim iResult(3) As Integer
'けど分子は4個とは限らないし、Nothingや0が入ってくることもあるとする
Dim iBunshi() As Integer
iBunshi = {Nothing, 0, 2}
'何があろうと割り算を4回実行する...
On Error Resume Next
For i As Integer = 0 To 3
iResult(i) = CInt(100 / iBunshi(i))
Next
On Error GoTo 0
'次の処理...
この例の場合、0で割っても、引数の配列が足りなくとも、処理は強引に続行されます。
iResultの中身は{0,0,50,0}となります。
直すにはResume Next~Goto 0の間の中身を見て、発生しそうなエラー全てをすくい取れるような条件分岐・Catchに置き換えていかないといけません。
こんなの触りたくないのが正直なところですが仕方ありません。
直した例がこちら。
'4回割り算したいと決まっているとする
Dim iResult(3) As Integer
'けど分子は4個とは限らないし、Nothingや0が入ることもあるとする
Dim iBunshi() As Integer
iBunshi = {Nothing, 0, 2}
'何があろうと割り算を4回実行する...
For i As Integer = 0 To 3
If iBunshi.Count <= i OrElse '引数が足りない
IsNothing(iBunshi(i)) OrElse 'Nothingが入っている
iBunshi(i) = 0 Then '0が入っている
iResult(i) = 0 'そんな場合は0を返す
Else
'正しい値なら割り算を実行
iResult(i) = CInt(100 / iBunshi(i))
End If
Next
'次の処理...
今回はTry-Catchなしで置き換えられる例でしたが、もちろんTry-Catchしないと難しいような処理のこともあります。
ケースバイケースで本当に面倒です。