3

堅牢性のために、TaskScheduler.UnobservedTaskExceptionのハンドラーを追加します。ハンドラーは例外をログに記録し、ユーザーに通知してアプリをシャットダウンします。

次の実装は意味がありますか?WPFでこのハンドラーにMessageBoxまたはWindowsを表示しても問題ありませんか、それとも監視されていないタスクのファイナライザーで実行しているため、これは悪い考えですか?

Private Sub TaskSheduler_UnobservedTaskException(sender As Object, e As UnobservedTaskExceptionEventArgs)
Static _wasUserInformed As Boolean = False

e.SetObserved()

'Trace all Exceptions
e.Exception.Flatten.Handle(Function(ex As Exception)
                               'TODO trace and log Exception
                               Debug.Print("UnobservedTaskException: {0}", ex.Message)
                               Return True
                           End Function)

If Not _wasUserInformed Then
    'Show root Exception 
    _wasUserInformed = True
    Application.Current.Dispatcher.BeginInvoke(Sub()
                                                   'MessageBox.Show(e.Exception.GetBaseException.Message)

                                                   Dim win As New UnexpectedExceptionWindow
                                                   win.UnexpectedException = e.Exception.GetBaseException
                                                   win.ShowDialog()

                                                   Application.Current.Dispatcher.BeginInvoke(Sub() Application.Current.Shutdown())
                                               End Sub)
End If

サブ終了

[編集]私たちの議論の結果、私は次の解決策を思いつきました。

Private Sub TaskScheduler_UnobservedTaskException(sender As Object, e As UnobservedTaskExceptionEventArgs
                                                  ) Handles TaskScheduler.UnobservedTaskException
    Static _wasUserInformed As Boolean = False

    'Free the finalizer thread and execute on the UI thread to be able to inform user
    Dispatcher.BeginInvoke(Sub() LogException(e.Exception))
    e.SetObserved()
    If Not _wasUserInformed Then
        _wasUserInformed = True
        'Show first error 
        Dispatcher.BeginInvoke(Sub()
                                   NotifyUser(e.Exception)
                                   Application.Current.Shutdown()
                               End Sub)
    End If
End Sub
4

1 に答える 1

1

これはとても良い質問です。このイベントはファイナライザースレッドで実行されているため(Reflectorで確認しました)、長期間ブロックする余裕はありません。これにより、ファイナライザーの処理が停止します。

したがって、答えは次のとおりです。UI操作の期間に制限がないため、これは適切な設計ではありません。

より良い解決策はTask、スレッドプールで実行されるように処理を新しいキューに入れることです。

この答えは、実装の詳細(ファイナライザーが単一のスレッドで実行され、イベントがファイナライザースレッドで発生する)によって異なります。ただし、少なくとも.NET 4.0をサポートするアプリの場合、この回答は有効です。

于 2012-09-01T21:16:33.570 に答える