Err.Clear と On Error GoTo -1 は同じ?!

## Err.Clear と On Error GoTo -1 は異なる

`Err.Clear`を使うと、それ以降の処理でエラーが発生した場合に、
エラーダイアログが表示されてしまう（Resume Nextが効かない）


## NGコード：エラーハンドラ内でエラーが発生したら無限ループに陥る

__NGコード__

``` vb
Sub Sample()
    On Error GoTo errHandler
    Debug.Print "Sub Sample()"
    
    Err.Raise (1) 'エラーが発生
    
    Debug.Print "Exit Sub"
Exit Sub
errHandler:
    On Error GoTo -1 'Errオブジェクトをクリア
    Debug.Print "errHandler:"
    
    Err.Raise (2) 'エラーハンドラ内で別のエラーが発生
    
    Debug.Print "End Sub"
End Sub
```

* 処理の流れ
    1. `Err.Raise (1)`：エラーが発生
    1. `On Error GoTo errHandler`により、errHandler:にジャンプ
    1. `On Error GoTo -1`：Errオブジェクトをクリア
    1. `Err.Raise (2)`：エラーハンドラ内で別のエラーが発生
    1. `On Error GoTo errHandler`により、：errHandler:にジャンプ

__出力__

``` sh
Sub Sample()
errHandler:
errHandler:
errHandler:
...
```


## エラーハンドラ内で発生したエラーは無視する

__コード__

``` vb
Sub Sample()
    On Error GoTo errHandler
    Debug.Print "Sub Sample()"
    
    Err.Raise (1) 'エラーが発生
    
    Debug.Print "Exit Sub"
Exit Sub
errHandler:
    On Error Resume Next '追加：エラーが発生したら、次の行から処理を継続
    On Error GoTo -1 'Errオブジェクトをクリア
    Debug.Print "errHandler:"
    
    Err.Raise (2) 'エラーハンドラ内で別のエラーが発生
    
    Debug.Print "End Sub"
End Sub
```

* 処理の流れ
    1. `Err.Raise (1)`：エラーが発生
    1. `On Error GoTo errHandler`により、errHandler:にジャンプ
    1. `On Error GoTo -1`：Errオブジェクトをクリア
    1. `Err.Raise (2)`：エラーハンドラ内で別のエラーが発生
    1. `On Error Resume Next`により、次の行から処理を継続

__出力__

``` sh
Sub Sample()
errHandler:
End Sub
```

> __メモ：`On Error Resume Next`と`On Error GoTo -1`の記述順__
> この2つは、記述順を前後させても同じ結果になった


## Err.ClearでもErrオブジェクトをクリアできる

``` vb
Sub Sample()
    On Error GoTo errHandler
    Debug.Print "Sub Sample()"
    
    Err.Raise (1) 'エラーが発生
    
    Debug.Print "Exit Sub"
Exit Sub
errHandler:
    On Error Resume Next 'エラーが発生したら、次の行から処理を継続
    Err.Clear '変更：Errオブジェクトをクリア
    Debug.Print "errHandler:"
    
    Err.Raise (2) 'エラーハンドラ内で別のエラーが発生
    
    Debug.Print "End Sub"
End Sub
```

* 処理の流れ
    1. `Err.Raise (1)`：エラーが発生
    1. `On Error GoTo errHandler`により、errHandler:にジャンプ
    1. `Err.Clear`：Errオブジェクトをクリア
    1. `Err.Raise (2)`：エラーハンドラ内で別のエラーが発生
    1. エラーダイアログが表示される  
![err2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2115724/c0792d82-eae9-1b68-2d14-0f1e240ddc88.png)

__出力__

``` sh
Sub Sample()
errHandler:
```

> __Err.Clear と On Error GoTo -1 の違い__
> `Err.Clear`を使うと、それ以降の処理でエラーが発生した場合に、
> エラーダイアログが表示される（Resume Nextが効かない）


## Err.Clearは自動的に実行される

マイクロソフトのドキュメントには、次のことが書かれている
> Err.Clearは、次のいずれかが実行される場合は必ず、自動的に呼び出される
> 
> * すべてのResumeステートメント
> * Exit Sub/Exit Function/Exit Property
> * On Error ステートメント
> 
> 参考：[Clear メソッド(VBA) - Microsoft Docs](<https://docs.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/clear-method-visual-basic-for-applications>)

もしそうなら、`On Error Resume Next`で自動的に`Err.Clear`されるので、
明示的に`Err.Clear`する必要はないのでは

先程のコードに`Debug.Print Err.Number`を2つ追加して検証してみる

``` vb
Sub Sample()
    On Error GoTo errHandler
    Debug.Print "Sub Sample()"
    
    Err.Raise (1) 'エラーが発生
    
    Debug.Print "Exit Sub"
Exit Sub
errHandler:
    Debug.Print Err.Number '追加：エラー番号を出力
    On Error Resume Next 'エラーが発生したら、次の行から処理を継続
    'Err.Clear '削除：Errオブジェクトをクリア
    Debug.Print Err.Number '追加：エラー番号を出力
    Debug.Print "errHandler:"
    
    Err.Raise (2) 'エラーハンドラ内で別のエラーが発生
    
    Debug.Print "End Sub"
End Sub
```

__出力__

``` sh
Sub Sample()
1
0
errHandler:
```

エラー番号が0なら、エラーの発生がない状態なので、
確かにクリアされている

> __補足：Exit Subではクリアされない?!__
> Exit Subが実行される場合に、Errオブジェクトがクリアされるか確認したが、
> されなかった。
> いろいろ試した結果、`On Error Goto xxx`のように、
> 何らかのエラーハンドラが設定されていないと、クリアされないみたい。


## 参考

参考にさせて頂いたサイト

* [VBAのエラー – エラー処理のベストプラクティス - Automate Excel](<https://www.automateexcel.com/ja/vba/error-handling-ja/>)

* [エラー処理（エラー内容をクリアする） - VBAの部品庫](<https://vbanobuhinko.com/エラー処理（エラー内容をクリアする）/>)


この記事を書くにあたり、「VBAの部品庫」さんの記事を参考にさせて頂きました。
その中で、「VBAの部品庫」さんの記事に掲載されているコードを次のように変更した方が
良いのではないかと思いました
※連絡先が見当たらないため、こちらに記載

__元のコード（「VBAの部品庫」さんの記事から引用）__

``` vb
エラー発生:
On Error GoTo 0
On Error Resume Next
'Err.Raise (1)
On Error GoTo -1
Err.Raise (1)
Debug.Print "エラー終了"
```

__変更したコード__

``` vb
エラー発生:

On Error Resume Next '暗黙的にErr.Clearされる
'Err.Raise (1) 'ここでエラーが発生した場合、前回のエラーは上書きされて消える
On Error GoTo -1 'On Error Resume Nextを有効にするため、再度、Errオブジェクトをクリア
Err.Raise (1)
Debug.Print "エラー終了"
```

## 追記

__変更したコード2__

エラーハンドラ内からプロシージャを呼び出す場合、
`On Error GoTo 0`が必要で、
プロシージャ内でエラーが発生する & プロシージャ内にエラーハンドラがない場合、
`エラー発生:`ラベルにジャンプするため、無限ループに陥る
※プロシージャを呼ぶ → プロシージャ内でエラー発生→`エラー発生`ラベルにジャンプ→プロシージャを呼ぶ→...

``` vb
エラー発生:
On Error GoTo 0
On Error Resume Next '暗黙的にErr.Clearされる
'Err.Raise (1) 'ここでエラーが発生した場合、前回のエラーは上書きされて消える
On Error GoTo -1 'On Error Resume Nextを有効にするため、再度、Errオブジェクトをクリア
Err.Raise (1)
Debug.Print "エラー終了"
```