73

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

バックグラウンド操作は、通常、誰かが再作成されているファイルを開いているときに、時折例外をスローします。

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

MSDNによると:

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

これらの例外がときどきスローされることを期待しており、DoWorkではなくRunWorkerCompletedイベントでそれらを処理したいと思います。私のコードは正しく機能し、エラーはRunWorkerCompletedイベント内で正しく処理されますが、「未処理の例外」の発生を訴える.NETエラーダイアログを停止する方法を私は一生理解できません。

BackgroundWorkerはそのエラーを自動的にキャッチすることになっているのではありませんか?それはMSDNのドキュメントに記載されていることではありませんか?RunWorkerCompletedEventArgsのErrorプロパティに例外をプロポーションさせながら、このエラー処理されていることを.NETに通知するにはどうすればよいですか?

4

5 に答える 5

139

あなたが説明しているのは、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にアクセスせずにそれを処理する必要があります。たとえば、次のコードはbad、bad、badであり、実行時に例外をスローします。

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、ランタイム例外は発生しません。

于 2009-06-25T15:34:03.250 に答える
41

私はMSDNテキストに追加します:

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

...そして、デバッガーは「〜Exceptionはユーザーコードによって処理されませんでした」として例外を報告します

解決策:デバッガーの下で実行しないでください。期待どおりに機能します。例外がe.Errorでキャッチされました。

于 2011-03-09T11:10:03.933 に答える
2

[編集]

ユダには素晴らしい点があります。私の例では、エラー処理の詳細を指摘しましたが、DoWorkメソッドで例外が発生しなかった場合、コードは実際には別の例外を引き起こします。この例は、BackgroundWorkerのエラー処理機能を具体的に示しているため、問題ありません。ただし、エラーパラメータをnullに対してチェックしていない場合は、これが問題である可能性があります。

[/編集]

同じ結果は表示されません。ちょっとしたコードを投稿してもらえますか?これが私のコードです。

private void Form1_Load(object sender, EventArgs e)
{
    BackgroundWorker worker = new BackgroundWorker();
    worker.DoWork += new DoWorkEventHandler(worker_DoWork);
    worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
    worker.RunWorkerAsync();
}

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // Will cause another exception if an exception didn't occur.
    // We should be checking to see if e.Error is not "null".
    textBox1.Text = "Error? " + e.Error;
}

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    for (int i = 0; i < 10; i++)
    {
        if (i < 5)
        {
            Thread.Sleep(100);
        }
        else
        {
            throw new Exception("BOOM");
        }   
    }
}

プログラム出力:

エラー?System.Exception:BOOM at BackgroundException.Form1.worker_DoWork(Object sender、DoWorkEventArgs e)in D:\ Workspaces \ Sandbox \ BackgroundException \ BackgroundException \ Form1.cs:line 43 at System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e)at System .ComponentModel.BackgroundWorker.WorkerThreadStart(オブジェクト引数)

あなたの質問に似た興味深い記事。例外の処理に関するセクションがあります。

http://www.developerdotstar.com/community/node/671

于 2009-06-25T15:10:38.303 に答える
2

これは古い質問ですが、同じ症状をグーグルで調べているときに見つけました。同じ理由で他の誰かが見つけた場合に備えて、これを投稿してください。

ユダの答えは正しいですが、「ユーザーコードで未処理の例外」ダイアログが表示されるのはそれだけではありません。バックグラウンドスレッドのコンストラクター内から例外がスローされた場合、その例外によってダイアログがすぐに発生し、RunWorkerCompletedイベントに渡されません。問題のあるコードをコンストラクターの外に(他のメソッドに)移動すると、期待どおりに機能します。

于 2012-03-20T21:59:58.503 に答える
0

私は同じ問題を抱えていました、そして私はいくつかのグーグルの後でこのトピックを見つける前にすでにユダの答えを適用していました。

ええと、ユダの答えは部分的に正しいです。私はここでより良い答えを見つけました

デバッガーは正常に機能しています。アプリケーションを「実際の条件」で実行すると、RunWorkerCompletedは期待どおりに例外を処理し、アプリケーションの動作も期待どおりになります。

この回答がお役に立てば幸いです。

于 2015-04-26T16:02:27.153 に答える