web-dev-qa-db-ja.com

Excel VBA:For-Loop内でError Gotoステートメントが機能しない

Excelでテーブルを循環しようとしています。この表の最初の3列にはテキスト見出しがあり、残りの列には見出しとして日付があります。これらの日付を日付型変数に順番に割り当て、日付に基づいていくつかの操作を実行したい

これを行うには、myTable.ListColumnsでforeachループを使用しています。最初の3つの列には日付ヘッダーがないため、ループを設定して、ヘッダー文字列を日付型変数に割り当てる際にエラーが発生した場合、ループが次の列に直接進むようにしました。

これは最初の列で機能するようです。ただし、2番目の列のヘッダーがdate-type変数に「割り当てられている」場合、マクロはエラー処理ブロック内にあるにもかかわらずエラーが発生します

Dim myCol As ListColumn
For Each myCol In myTable.ListColumns
    On Error GoTo NextCol

    Dim myDate As Date
    myDate = CDate(myCol.Name)

    On Error GoTo 0

    'MORE CODE HERE

NextCol:
    On Error GoTo 0
Next myCol

繰り返しになりますが、エラーはループの第2ラウンドのステートメントでスローされます

myDate = CDate(myCol.Name)

On Errorステートメントが機能しなくなる理由を説明できる人はいますか?

16
Swiftslide

示されているコードでは、nextステートメントを実行したときのエラー処理ルーチンはwithinであるとみなされています。

つまり、現在のエラーハンドラから再開するまで、後続のエラーハンドラは許可されません。

より良いアーキテクチャは次のとおりです。

    Dim myCol As ListColumn
    For Each myCol In myTable.ListColumns
        On Error GoTo ErrCol
        Dim myDate As Date
        myDate = CDate(myCol.Name)
        On Error GoTo 0
        ' MORE CODE HERE '
NextCol:
    Next myCol
    Exit Sub ' or something '

ErrCol:
    Resume NextCol

これにより、通常のコードからのエラー処理が明確になり、別のハンドラーをセットアップする前に現在実行中のエラーハンドラーが終了することが保証されます。

このサイト には問題の説明があります:


エラー処理ブロックとエラー時Goto

エラーハンドラーとも呼ばれるエラー処理ブロックは、On Error Goto <label>:ステートメントを介して実行が転送されるコードのセクションです。このコードは、問題を修正してメインコードブロックで実行を再開するか、プロシージャの実行を終了するように設計する必要があります。 On Error Goto <label>:ステートメントは、行をスキップするだけでは使用できません。たとえば、次のコードは正しく機能しません。

    On Error GoTo Err1:
    Debug.Print 1 / 0
    ' more code
Err1:
    On Error GoTo Err2:
    Debug.Print 1 / 0
    ' more code
Err2:

最初のエラーが発生すると、実行はErr1:に続く行に移動します。エラーハンドラーは、2番目のエラーが発生したときにまだアクティブであるため、2番目のエラーはOn Errorステートメントによってトラップされません。

33
paxdiablo

エラー処理が終わったことを示すために、エラー処理コードにある種のresumeを追加する必要があります。それ以外の場合、最初のエラーハンドラはまだアクティブであり、「解決」されることはありません。

http://www.cpearson.com/Excel/errorhandling.htm を参照してください(具体的には「エラー処理ブロックとエラー後処理」という見出しと次のセクション)

8
enderland

Paxdiabloの受け入れられた回答のフォローアップ。これは可能で、同じサブで2つのエラートラップを次々に許可します。

Public Sub test()
    On Error GoTo Err1:
    Debug.Print 1 / 0
    ' more code
Err1:
    On Error GoTo -1     ' clears the active error handler
    On Error GoTo Err2:  ' .. so we can set up another
    Debug.Print 1 / 0
    ' more code
Err2:
    MsgBox "Got here safely"
End Sub

On Error GoTo -1を使用すると、アクティブなエラーハンドラーがキャンセルされ、別のエラーハンドラーをセットアップできます(そしてerr.clearはこれを行いません!)。これが良いアイデアであるかどうかは、読者の課題として残されていますが、うまくいきます!

5
AjV Jsy

Errオブジェクトのすべてのプロパティ設定をクリアすることは、エラーハンドラーをリセットすることとは異なります。

これを試して:

Sub TestErr()
Dim i As Integer
Dim x As Double
    On Error GoTo NextLoop
    For i = 1 To 2
10:     x = i / 0
NextLoop:
        If Err <> 0 Then
            Err.Clear
            Debug.Print "Cleared i=" & i
        End If
    Next
End Sub

OPと同じように、i =1しかし、i = 2、使用したのはErr.Clear

0
Profex