【VB6・VB】古いコードのリプレース　その３　On Error ～

**※この記事は[【VB6・VB】古いコードのリプレース](https://qiita.com/so_rei/items/62a0327d321a5e0dd279) のシリーズその３です。**


#On Errorステートメントとは

VB6時代からあるエラー対処法。

最も簡単な例がこちら

```VB6.0:VB6：hoge.vb
        On Error GoTo Err
        '処理...
        '..
Err:
```

最初に断っておきますが、これは今でも使えます。
けど少なくとも、今から新しく書くような用法ではないです。

なぜなら、Try-Catchがあるから。

#Try-Catchとは

VBから出来たエラー対処法。

```VB:VB：hoge.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　通常の置き換え](#例1通常の置き換え)
[例2　Err.Numberがあるとき](#例2-errnumberがあるとき)
[例3　Resume Next / Goto 0　がある場合](#例3resume-next--goto-0がある場合)


##例1　通常の置き換え

通常の置き換えはさきほどの例そのままです。

##例2 Err.Numberがあるとき

```VB6.0:VB6：例
        On Error GoTo Err
        '処理...
        '..
Err:
    If Err.Number = 53 Then
    '特別なエラー処理..
    End If
    '普通のエラー処理..
```

ErrObjectの.Numberの値によって個別で何か処理をやっている場合。
この場合、そのエラーが一体何のエラーなのか調べて、そのエラーと対応するExceptionを探さないといけません。

**NumberとExceptionは１：１で対応しているわけではありません。
内容を見て実際に動かして確認するしかありません。**

よくErr.Numberで特殊対応しているのを見るのは↓あたりでしょうか。

|     .Number       | .Description |
|:-----------------------|------------------:|
| 5|プロシージャの呼び出し、または引数が不正です。|
| 9|  インデックスが有効範囲にありません。      |
|11| 	0 で除算しました。|
|13| 	型が一致しません。|
|53|ファイルが見つかりません。または存在しないファイルを参照しています。|
|75|  	 パス名が無効です。 |
|76| 	 パスが見つかりません。|
|321| 	不正なファイル形式です。|
|31036|ファイルへの書き込み中にエラーが発生しました。 	|
|31037|ファイルの読み込み中にエラーが発生しました。 	|


特にVB6はファイルとのやりとりがお粗末なものしかなかったので、ファイル関係のエラートラップが多いかと思います。
たとえば上のErr.Number=53「ファイルが見つかりません。または存在しないファイルを参照しています。」
の場合は、以下のような変更でいいでしょう。
(IOExceptionもあったほうが安全かも）

```VB:VB：例
        Try
            '処理..
        Catch ex As System.IO.FileNotFoundException
            '特別なエラー処理..
        Catch ex As Exception
            '普通のエラー処理..
        End Try
```


##例3　Resume Next / Goto 0　がある場合

Resume Nextは出たエラーを無視してそのまま次の処理へ進むため、本当に現在の設計思想からしたらメチャクチャな動きをします。
無視する範囲の終わりにOn Error Goto 0とつけるのが基本的な使用方法です。

例えば、こういうコードが書けます。

```VB6.0:VB6：例

        '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に置き換えていかないといけません。
こんなの触りたくないのが正直なところですが仕方ありません。

直した例がこちら。

```VB:VB：例

        '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しないと難しいような処理のこともあります。
ケースバイケースで本当に面倒です。