1. ホーム
  2. c#

BackgroundWorkerの未処理例外について

2023-12-04 01:20:11

質問

私は、BackgroundWorkerオブジェクトを利用して長時間実行する小さなWinFormsアプリを持っています。

バックグラウンド操作では、誰かがファイルを開いていて、それが再作成されるときなど、時折例外が発生します。

コードが IDE から実行されるかどうかに関係なく、.NET はユーザーに未処理の例外が発生したことを通知するエラー ダイアログをポップアップ表示します。 Release 構成を使用してコードをコンパイルしても、これは変わりません。

によると MSDN :

<ブロッククオート

コードが処理しない例外を発生させた場合、BackgroundWorker は例外をキャッチして RunWorkerCompleted イベント ハンドラーに渡し、そこで System.ComponentModel...:.RunWorkerCompletedEventArgs の Error プロパティとして公開されます。Visual Studio デバッガーの下で実行している場合、デバッガーは DoWork イベント ハンドラーで未処理の例外が発生した箇所でブレークします。

これらの例外が時々スローされることを期待し、DoWork 内ではなく RunWorkerCompleted イベントで処理したいと思います。 私のコードは適切に動作し、エラーは RunWorkerCompleted イベント内で正しく処理されますが、"Unhandled exception" について文句を言う .NET エラー ダイアログの発生を停止する方法がどうしてもわかりません。

BackgroundWorker はそのエラーを自動的にキャッチするはずではありませんか? MSDN のドキュメントにはそのように記載されていないのでしょうか? .NET に、このエラー が処理されていることを.NETに知らせると同時に、例外がRunWorkerCompletedEventArgsのErrorプロパティに伝播することを可能にする必要がありますか?

どのように解決するのですか?

あなたが記述していることは、BackgroundWorkerの定義された動作ではありません。何か間違ったことをしているのではないでしょうか。

以下はBackgroundWorkerが例外を食べることを証明する小さなサンプルです。 DoWork で例外を受け取り、それを RunWorkerCompleted :

var worker = new BackgroundWorker();
worker.DoWork += (sender, e) => 
    { 
        throw new InvalidOperationException("oh shiznit!"); 
    };
worker.RunWorkerCompleted += (sender, e) =>
    {
        if(e.Error != null)
        {
            MessageBox.Show("There was an error! " + e.Error.ToString());
        }
    };
worker.RunWorkerAsync();

私のサイキックデバッグスキルが、あなたの問題を明らかにしてくれています。RunWorkerCompleted ハンドラで e.Result にアクセスしています。もし e.Error があれば、e.Result にアクセスせずに処理する必要があります。たとえば、次のコードは悪い、悪い、悪い、実行時に例外をスローします。

var worker = new BackgroundWorker();
worker.DoWork += (sender, e) => 
    { 
        throw new InvalidOperationException("oh shiznit!"); 
    };
worker.RunWorkerCompleted += (sender, e) =>
    {
        // OH NOOOOOOOES! Runtime exception, you can't access e.Result if there's an
        // error. You can check for errors using e.Error.
        var result = e.Result; 
    };
worker.RunWorkerAsync();

RunWorkerCompletedイベントハンドラの適切な実装を紹介します。

private void RunWorkerCompletedHandler(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Error == null)
    {
       DoSomethingWith(e.Result); // Access e.Result only if no error occurred.
    }
}

VOILA, ランタイムエクストラクションを受けなくなります。