4

.NET 2.0アプリでの例外処理の修正に取り組んでいたところ、Application.ThreadExceptionの奇妙な問題に遭遇しました。

私が欲しいのは、GUI要素の背後にあるイベント(たとえば、button_Clickなど)からのすべての例外をキャッチできるようにすることです。次に、これらの例外を「致命的」でフィルタリングしたいと思います。たとえば、あるタイプの例外ではアプリケーションを実行し続け、他のタイプではアプリケーションを終了する必要があります。

別の.NET2.0アプリでは、デフォルトでは、デバッグモードでのみ、例外が実際にApplication.RunまたはApplication.DoEvents呼び出しを残すことを学びました。リリースモードではこれは発生せず、Application.ThreadExceptionイベントを使用して例外を「キャッチ」する必要があります。

ただし、Application.ThreadExceptionイベントのThreadExceptionEventArgsで渡される例外オブジェクトは、常に例外チェーンの最も内側の例外であることに気付きました。ただし、ロギング/デバッグ/設計の目的で、例外のチェーン全体が本当に必要です。たとえば、SocketExceptionを処理するだけの場合、どの外部システムが失敗したかを判断するのは簡単ではありません。たとえば、NpgsqlExceptionとしてラップされている場合、少なくともデータベースの問題であることがわかります。

では、このイベントからの例外のチェーン全体に到達するにはどうすればよいですか?それも可能ですか、それとも別の方法で例外処理を設計する必要がありますか?

Application.SetUnhandledExceptionModeを使用して回避策がありますが、独自のメッセージループをロールする必要があるため、これは理想からはほど遠いことに注意してください。

編集:より多くの間違いを防ぐために、GetBaseException()メソッドは私が望むことをしません:それはただ最も内側の例外を返しますが、私がすでに持っているのは最も内側の例外だけです。一番外側の例外を取得したいです!

4

7 に答える 7

3

この質問は、より便利に表現され、ここで回答されています。

実際にスローされた例外ではなく、内部例外が ThreadException ハンドラーに到達するのはなぜですか?

于 2009-08-04T17:25:26.963 に答える
1

通常、例外が他のスレッドで発生した場合、Application.ThreadException例外ハンドラーの基本例外を除いて、例外チェーン全体が失われるだけです。

MSDNライブラリから:

このイベントにより、Windowsフォームアプリケーションは、 Windowsフォームスレッドで発生する未処理の例外を処理できます 。イベントハンドラーをThreadExceptionイベントにアタッチして、これらの例外を処理します。これにより、アプリケーションが不明な状態になります。可能な場合、例外は構造化された例外処理ブロックによって処理される必要があります。

解決策:スレッド化を行う場合は、すべてのスレッド/非同期呼び出しがtry/catchブロックにあることを確認してください。または、あなたが言ったように、Application.SetUnhandledExceptionModeで遊ぶことができます。

于 2008-11-21T10:58:24.420 に答える
1

私はこの動作を再現しようとしました (常に最も内側の例外を取得します)
が、すべての InnerExceptions がそのままの状態で、期待どおりの例外を取得します。

テストに使用したコードは次のとおりです。

   Private Shared Sub Test1()
      Try
         Test2()
      Catch ex As Exception
         Application.OnThreadException(New ApplicationException("test1", ex))
      End Try
   End Sub

   Private Shared Sub Test2()
      Try
         Test3()
      Catch ex As Exception
         Throw New ApplicationException("test2", ex)
      End Try
   End Sub

   Private Shared Sub Test3()
      Throw New ApplicationException("blabla")
   End Sub

Private Shared Sub HandleAppException(ByVal sender As Object, ByVal e As ThreadExceptionEventArgs)
...
End Sub

Sub HandleAppException は、Application.ThreadException を処理します。Test1() メソッドが最初に呼び出されます。
これは、HandleAppException で取得した結果 (e As ThreadExceptionEventArgs) です。

ThreadException http://mediasensation.be/dump/?download=ThreadException.jpg

例外をキャッチして (再) スローするだけの場合、InnerExceptions は表示されませんが、例外に追加されます。StackTrace、次のように:

Test.vb の SO.Test3(): 166 行目
Test.vb の SO.Test2(): 159 行
目 Test.vb の SO.Test1(): 151 行目

于 2008-11-21T10:41:35.843 に答える
1

面白いことを発見しました。GUI イベントが異なれば、結果も異なります。Form.Shown イベント ハンドラーから例外がスローされると、Application.ThreadException が最も内側の例外をキャッチしますが、まったく同じコードを Form.Load イベントで実行すると、最も外側の例外が Application.ThreadException でキャッチされます。

于 2009-12-09T02:06:45.873 に答える
0

Exception.GetBaseExceptionメソッドを試しましたか?これにより、Application.TreadExceptionを作成した例外が返されます。次に、同じプロセスを使用してチェーンを上に移動し、すべての例外を取得できます。

exception.getbaseexceptionメソッド

于 2008-09-14T14:18:04.360 に答える
-1

MSDNのドキュメントによると:

派生クラスでオーバーライドされると、後続の 1 つ以上の例外の根本原因である Exception を返します。

    Public Overridable Function GetBaseException() As Exception
        Dim innerException As Exception = Me.InnerException
        Dim exception2 As Exception = Me
        Do While (Not innerException Is Nothing)
            exception2 = innerException
            innerException = innerException.InnerException
        Loop
        Return exception2
    End Function

これのバリエーションを使用して、例外チェーンを解析できます。

Public Sub LogExceptionChain(ByVal CurrentException As Exception)

    Dim innerException As Exception = CurrentException.InnerException
    Dim exception2 As Exception = CurrentException

    Debug.Print(exception2.Message) 'Log the Exception

    Do While (Not innerException Is Nothing)

        exception2 = innerException
        Debug.Print(exception2.Message) 'Log the Exception

        'Move to the next exception
        innerException = innerException.InnerException
    Loop

End Sub

これはまさにあなたが探しているものだと思います。

于 2008-09-14T21:03:27.210 に答える