- PR -

BackgroundWorkerでの例外補足ができません

1
投稿者投稿内容
lifeline
会議室デビュー日: 2009/03/25
投稿数: 3
投稿日時: 2009-03-25 17:18
環境:Visual Studio 2008 (SP1)

BackgroundWorkerを用いたバックグラウンド処理を実行中、
バックグラウンドで実行中のメソッドで発生した例外の処理が
想定通りうまくいきません。

期待している挙動は下記の通りです。

1. BackgroundWorker1_DoWork()イベントプロシージャが実行される。
2. 同イベントプロシージャ内でコールされるメソッド@が実行される。
3. メソッド@で例外発生
4. BackgroundWorker1_RunWorkerCompleted()イベントプロシージャが実行される。
5. 同イベントプロシージャ内でe.Errorを判定する。
 例外が発生していればe.ErrorはNothingではないという認識の為、
 下記の判定を行い例外処理をする。
コード:

If Not (e.Error Is Nothing) Then
・・・例外時の処理
Endif


ここで、「3」で例外が発生したときに、下記のエラーメッセージが出力され
デバッグが停止してしまいます。
 「xxxxx はユーザーコードによってハンドルされませんでした。」

過去ログを参照して
 ・VisualStudioのメニュー「デバッグ>例外」でユーザにハンドルされていなときの
 設定(Common Language Runtime Exception)をチェックオフにして再度実行。

コード上で止まることはなくなりましたが、上記「5」の部分で判定にひっかかりません。e.Error がセットされていなようです。

BackgroundWorker1_DoWork()イベントプロシージャでTry Catchしてthrowはしないという認識なのでしておりませんが、Try Catchを記述した場合、Catch節にて発生されたエラーメッセージが出力されるので例外は飛んできています。
 →Throwした場合は上述と同じエラーメッセージが出力されます。

そもそも、このようなケースにおいて根本的な例外処理のしかたが間違っているのでしょうか。
 →DoWorkイベントプロシージャ内でTry Catch節で例外を細くして、
  イベントにエラー設定などをしてやらなければいけないのでしょうか。

ソースを掲載させていただきます。
コード:

Private Sub BackgroundWorker1_DoWork()

' 長時間実行処理
BGMethod()

End Sub

Private Sub BackgroundWorker1_RunWorkerCompleted()

If Not (e.Error Is Nothing) Then
// 例外処理
ElseIf e.Cancelled Then
// キャンセル時の処理
Else
// 正常終了の処理
End If

End Sub

Private Sub BGMethod()
System.Threading.Thread.Sleep(5000) // 長時間実行処理のエミュレート

Console.Writeline(CInt("a")) // わざと例外を発生させる。

End Sub




[ メッセージ編集済み 編集者: lifeline 編集日時 2009-03-25 17:45 ]
lifeline
会議室デビュー日: 2009/03/25
投稿数: 3
投稿日時: 2009-03-25 17:44
もう少し調査をしてみたところ、

 bgWorker_DoWorkメソッド内で、DoWorkEventArgs.Resultに処理結果を設定して、
 RunWorkerCompletedイベントハンドラで結果を受け取って処理をする。

という方法がありましたので、DoWorkイベントプロシージャ内にて
コード:

Try
BGMethod()

Catch ex As Exception
e.Result = 9
End Try


という記述で、RunWorkerCompletedイベントプロシージャにてその値を判断する
という方法が使えることがわかりましたが、このような方法は一般的なのでしょうか。
根本的な原因(例外時にe.Errorがセットされない)の解決にはならないのですが。


[ メッセージ編集済み 編集者: lifeline 編集日時 2009-03-25 17:45 ]
くまっち
大ベテラン
会議室デビュー日: 2008/01/18
投稿数: 169
お住まい・勤務地: 茨城県のどこか。
投稿日時: 2009-03-25 22:35
うーん・・・
> e.Error がセットされていなようです。
とは・・・止めて見た結果Nothingだったのですか?

「ユーザーコードによってハンドルされてない〜」
は発生してもそのままF5で続行させると
きちんとe.Errorに入って来るはずですが。。。

方法 : バックグラウンドで操作を実行する
lifeline
会議室デビュー日: 2009/03/25
投稿数: 3
投稿日時: 2009-03-26 01:57
>くまっちさん

>「ユーザーコードによってハンドルされてない〜」
>は発生してもそのままF5で続行させると
>きちんとe.Errorに入って来るはずですが。。。
 はい。
 上述のコードでe.ErrorがNothingでIF文判定にかからないないのです。
 DoWork()でe.Resultをセットして、Completed()でその値を判断してそこで例外を
 飛ばすように対応したのですが、とても気持ちが悪くどうしたものかと。。。
Toshi
ベテラン
会議室デビュー日: 2007/09/18
投稿数: 68
お住まい・勤務地: 関東のどっか
投稿日時: 2009-03-26 10:12
こんにちわ。

引用:

コード上で止まることはなくなりましたが、上記「5」の部分で判定にひっかかりません。e.Error がセットされていなようです。


これはどのように確認されました?
実行結果からの推測ではなく、ブレイクポイントを置いて確認されたのでしょうか?

いずれにせよ、lifelineさんの一番初めの認識で問題はないはずです。
ちょっと気になるのは、記載いただいたコードの一部、おそらく省略していますよね?
(引数だとか・・)
そのあたりに原因があるかもしれません。

尚、以下のコードでは、e.ErrorにExceptionが格納されていました。

コード:

Public Class Form1

Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim val As Integer = CInt("a")
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Me.BackgroundWorker1.RunWorkerAsync()
End Sub

Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
If Not (e.Error Is Nothing) Then
MessageBox.Show("Exception有り")
End If
End Sub
End Class



ご参考までに

[ メッセージ編集済み 編集者: Toshi 編集日時 2009-03-26 10:13 ]
1

スキルアップ/キャリアアップ(JOB@IT)