12

コードの特定のビットが予期した方法でエラーを発生させることがありますが、同じタイプの他のエラーと混同されるエラー処理ルーチンにエラーをスローするよりも、ローカルで処理する方が最も便利です。それでも、予期しないエラーを飲み込みたくはありません。あなたは彼らをいつものように育てたいと思っています。

以下の (少し不自然な) 例では、FindInArray関数はさまざまな種類のエラーを発生させる可能性があります。そのうちの 1 つであるERR__ELEMENT_NOT_FOUND_IN_ARRAYは多かれ少なかれ予想されるので、ローカルで処理したいと考えています。しかし、他のエラー番号も発生する可能性があり、その場合はエラー処理ルーチンで処理する必要があります。

予想されるエラー番号をローカルで処理すると、予期しないエラー番号を別の場所で処理するために簡単に「再スロー」することができないことがわかりました。

エラー処理ルーチン (または他の場所) で処理される予期しないエラーから、ローカルで処理したい予期されるエラーを分離するにはどうすればよいですか?

On Error GoTo ErrorHandler

'Some code...

'Here I want to trap a likely/expected error locally, because the same
'error may occur elsewhere in the procedure but require different handling.
On Error Resume Next
personIndex = FindInArray(personName, personArray)
If Err.Number = ERR__ELEMENT_NOT_FOUND_IN_ARRAY Then
    MsgBox "Name not found in person array. Using default person."
Else
    'What if it's a different kind of error?
    ' .e.g. ERR__ARRAY_CONTAINS_TWO_PERSONS_WITH_SAME_NAME
    'I want to rethrow it, but can't because On Error Resume Next swallows it.
End If
On Error GoTo ErrorHandler 'back to normal
'I can't rethrow it here either, because On Error Goto cleared the Err object.

'-----------------------
ErrorHandler:
Select Case Err.Number
Case ERR__ELEMENT_NOT_FOUND_IN_ARRAY
    'The error number doesn't give me enough info 
    'to know what to do with it here!
Case ERR__ARRAY_CONTAINS_TWO_PERSONS_WITH_SAME_NAME
    'Existing code to deal with this error
Case ...

エラー番号、ソース、説明などを他の変数/オブジェクトに「保存」し、それらを使用して後でエラーを発生させることができるOn Error GoTo ErrorHandler 'back to normalと思います(実際、これを確認するために実装しました)が、それはひどく不便に思えますそして不器用。

4

4 に答える 4

3

私は尋ねられた質問に少し混乱していますが (そして、今まで何度も読み返してきました :-))、このジレンマの原因は関数スコープ内にあると非常に強く感じています。
よろしければ、パターンを示す基本的な例をいくつか使用しますが、コードとは 1 対 1 ではありません。

エラー処理ルーチン (または他の場所) で処理される予期しないエラーから、ローカルで処理したい予期されるエラーを分離するにはどうすればよいですか?

答えは質問自体にあるような気がします。
エラー ハンドラは、下位レベルのサブ ルーチンまたは関数から呼び出すサブ ルーチン/関数のローカル スコープ内で機能します。

予想されるエラー番号をローカルで処理すると、予期しないエラー番号を別の場所で処理するために簡単に「再スロー」することができないことがわかりました。

ローカルエラーをチェックしたいコードを、 の特定のレベルの上に配置する外部関数/サブルーチンに委譲する場合に可能ですcall stack。独自のスコープ内でエラーを処理するため、互いに混同することはありません。

次のコードを検討してください。

Sub baseSub()

    Dim n As Integer

    n = checkDivision(1, 0)      
    n = 1 / 0  ' cause an error

End Sub

Public Function checkDivision(iNumerator As Integer, iDenominator As Integer)

    On Error Resume Next
    checkDivision = iNumerator / iDenominator

    If Err.Number <> 0 Then
        checkDivision = Err.Number
        Exit Function
    End If

End Function

反対にOn Error Resume Next baseSubから適用する場合、コール スタックの一番上に配置されたすべての関数もエラーを無視します。しかし、それは逆には機能しません。

これを有利に利用できると思います。

結論として、コール スタックの上位レベルに配置する委譲関数で予想されるエラーをトラップすることで、問題を解決できると思います。

これがうまくいかない場合、私はアイデアがありません。

于 2013-12-11T10:06:54.020 に答える
3

この答えは、目前の問題についての私の意見であり、おそらく少し異なる角度から見たものです。

このコード ブロックを検討する場合:

On Error Resume Next
personIndex = FindInArray(personName, personArray)
If Err.Number = ERR__ELEMENT_NOT_FOUND_IN_ARRAY Then
    MsgBox "Name not found in person array. Using default person."
Else
End If

タイトルに「予想されるエラー」と記載されています。
ただし、エラーが発生する可能性があることが事前にわかっている場合は、エラーをスローしないでください。
それらは、validation私の意見では、条件ステートメントの形で関数に組み込まれるべき形式です。

前述のコード ブロックは、基本的なレベルでは次のようになります。

    If Not (in_array(vArray, "Jean-Francois")) Then
        MsgBox "Name not found in person array. Using default person."
    End If

私の意見では、これはずっとクリーンで読みやすいものです。
基本コードの一部ではないが、バックグラウンドでチェックを行うカスタム関数を使用します。再利用可能な関数は、静的クラスと非常によく似た方法で使用するモジュールにラップできます。

Public Function in_array(vArray As Variant, sItem As String) As Boolean

    Dim lCnt As Long

    in_array = False
    Do Until lCnt = UBound(vArray) + 1
        If StrComp(vArray(lCnt), sItem, CompareMethod.Text) = 0 Then
            in_array = True
            Exit Function
        End If
        lCnt = lCnt + 1
    Loop

End Function

さらに良いのは、in_array()関数内から関数を使用findInArray()し、basesub に 1 行のコードのみを含めることです。これは次のようになります。

personIndex = FindInArray(personName, personArray)

後ろの関数に残りを処理させ、予測できる例外をインターセプトします。
これは単なる例です。明らかに、自分にとって有用な関数と戻り値を記述し、おそらくより広範な検証を追加できます。

私の要点は、これらの戻り値はアプリケーション/検証ロジックの一部である戻りメッセージであり、技術的なエラーとは見なされないということです。したがって、それらのエラーハンドラーをカスタムとして使用する利点はありません作成された関数は、(私の意見では)よりクリーンな構造でニーズに正確に適合します。

たとえば、関数呼び出しに 3 つの引数を渡して、2 つしか受け付けない場合は、技術的なエラーと見なします。エラー ハンドラーが通知します。その後、開発者は現在の関数をより動的にすることを決定できます。オプションのパラメーターとバグの修正。

于 2013-12-10T15:46:04.340 に答える