私のWinFormsアプリは、いくつかの BackgroundWorker オブジェクトを使用して、データベースから情報を取得します。 BackgroundWorkerを使用しているのは、データベースクエリが長時間実行されている間もUIのブロックを解除でき、スレッドモデルが簡略化されるためです。
これらのバックグラウンドスレッドの一部で時々DatabaseExceptionsが発生し、デバッグ中にワーカースレッドでこれらの例外の少なくとも1つを目撃しました。これらの例外はタイムアウトであると私はかなり確信しています。
私の質問は、これらのバックグラウンドワーカースレッドの1つで未処理の例外が発生したときに何が起こるかについてです。
別のスレッドで例外をキャッチできるとは思いませんが、WorkerCompletedメソッドが実行されることを期待できますか?例外を問い合わせできるBackgroundWorkerのプロパティまたはメソッドはありますか?
コードで処理できない例外が操作によって発生した場合、BackgroundWorker
は例外をキャッチしてRunWorkerCompleted
イベントハンドラーに渡し、System.ComponentModel.RunWorkerCompletedEventArgs
のErrorプロパティとして公開されます。 Visual Studioデバッガーで実行している場合、デバッガーは、未処理の例外が発生したDoWorkイベントハンドラーのポイントで中断します。
http://msdn.Microsoft.com/en-us/library/system.componentmodel.backgroundworker.dowork.aspx
私は何年にもわたってBackgroundWorker
を完全に使用しており、本当に深く理解しています。
つい最近、RunWorkerCompleted
で単にThrow New Exception("Test")
とすると、My DoWork
は_e.Error
_をキャッチしません。ただし、未処理の例外が発生しました。 DoWork
でのキャッチはベストプラクティスではないため、_e.Error
_は意味を持ちません。
新しいForm
で新しいBackgroundWorker
を作成しようとすると、RunWorkerCompleted
の_e.Error
_が正常に処理されました。複雑なBackgroundWorker
に問題があるはずです。
数日後、グーグルしてデバッグし、エラーを試します。私のRunWorkerCompleted
にこれが見つかりました:
e.Error
_をチェックし、次に_e.Cancelled
_、最後に_e.Result
_を確認しますe.Result
_の場合、_e.Cancelled = True
_を取得しません。e.Result
_がnull
(またはNothing
)でない場合、_e.Error
_を取得しません****これは私が恋しいところです。 _e.Result
_がnull
(またはNothing
)でない場合に_e.Error
_を使用しようとすると、未処理の例外がスローされます。
PDATE: _e.Result
_ getプロパティ.NETでは、最初に_e.Error
_をチェックするように設計し、エラーが発生した場合はDoWork
。そのため、RunWorkerCompleted
で未処理の例外が発生しますが、実際にはDoWork
から例外が発生します。
RunWorkerCompleted
で行うベストプラクティスは次のとおりです。
_If e.Error IsNot Nothing Then
' Handle the error here
Else
If e.Cancelled Then
' Tell user the process canceled here
Else
' Tell user the process completed
' and you can use e.Result only here.
End If
End If
_
すべてのDoWork、ProgressChanged、およびRunWorkerCompletedからアクセスできるオブジェクトが必要な場合は、次のように使用します。
_Dim ThreadInfos as Dictionary(Of BackgroundWorker, YourObjectOrStruct)
_
どこでも簡単にThreadInfos(sender).Field
にアクセスできます。
デフォルトでは、BackgroundWorkerによってキャッチおよび保存されます。 MSDNから:
操作でコードが処理しない例外が発生すると、BackgroundWorkerが例外をキャッチし、それをRunWorkerCompletedイベントハンドラーに渡します。そこで、System.ComponentModel.RunWorkerCompletedEventArgsのErrorプロパティとして公開されます。 Visual Studioデバッガーで実行している場合、デバッガーは、未処理の例外が発生したDoWorkイベントハンドラーのポイントで中断します。
すでに述べたように:
操作でコードが処理しない例外が発生すると、BackgroundWorkerが例外をキャッチし、それをRunWorkerCompletedイベントハンドラーに渡します。そこで、System.ComponentModel.RunWorkerCompletedEventArgsのErrorプロパティとして公開されます。
これは、元のスレッドを操作しているときはいつでも重要です。たとえば、例外の結果をフォームのある種のラベルに書き込む場合は、BackgroundWorkerのDoWorkで例外をキャッチするのではなく、RunWorkerCompletedEventArgsからe.Errorを処理する必要があります。
リフレクターを使用してBackgroundWorkerコードを分析すると、そのすべてがかなり簡単に処理されていることがわかります。DoWorkはtry-catchブロックで実行され、例外はRunWorkerCompletedに渡されるだけです。これが、DoWorkイベントですべての例外を常にキャッチする「推奨」方法に同意しない理由です。
つまり、元の質問に答えるには:
はい-RunWorkerCompletedが常に起動されることを期待できます。
RunWorkerCompletedのe.Errorを使用して、他のスレッドの例外を確認します。
これは、デバッガーが接続されていない場合にのみ機能します。VisualStudioから実行すると、デバッガーはDoWorkメソッドでハンドレス例外をキャッチして実行を中断しますが、続行をクリックするとRunWorkerCompletedに到達し、例外を読み取ることができますe.Errorフィールドを介して。