2

動機

を使用してスローされた例外を処理し、メイン UI スレッドで例外を再スローTaskするWindows.Formsアプリケーションで を使用しています。TaskTask.ContinueWith()Control.Invoke()

ただし、使用すると例外に気付くことができませんでしたが、使用するControl.Invoke()と機能しますControl.BeginInvoke()

で動作しない理由とControl.Invoke()、動作させる方法を知っている人はいますか?

回避策

私は現在、使用Control.BeginInvoke()する代わりに投げるために使用していますControl.Invoke()

再現する手順

環境: Windows 7 x64、Visual Studio 2012、.Net 4 用にコンパイル (ただし、.Net 4.5 は VS2012 の一部としてインストールされます)。

(1) というフォームで既定の Windows フォーム アプリを作成しますform1

(2) というフォームにボタンを配置し、button1というハンドラーを追加しbutton1_Click()ます。

(3) 次のように実装button1_Click()します。

private void button1_Click(object sender, EventArgs e)
{
    Task.Factory.StartNew(() =>
    {
        Thread.Sleep(1000);
        this.BeginInvoke(new Action(() =>
        {
            throw new InvalidOperationException("TEST");
        }));
    });
}

(4) プログラムを実行し、 ボタンをクリックします。1 秒後、期待どおりに例外ダイアログが表示されます。

(5) に変更this.BeginInvokethis.Invokeます。

(6) プログラムを再度実行し、 ボタンをクリックします。これで、例外は黙って無視されます!

指定された の UI スレッドでInvoke()との両方が実行されるため、例外が無視される理由と無視されない理由がわかりません...BeginInvoke()Control

例外がスローされた場合に返されないという事実と関係があるに違いないと推測していますControl.Invoke()が、例外が(明らかに)完全に無視されることを意味する理由を理解しようとすると、頭が痛くなります。

4

1 に答える 1

3

これは仕様によるもので、Invoke() は BeginInvoke() とは異なる方法で例外を処理します。呼び出されたメソッドが失敗したことがわかるように、例外をマーシャリングして再スローします。これは、スレッドが既に移動しているため、BeginInvoke() では機能しないため、UI スレッドで発生します。次の問題は、Task クラスが例外を飲み込むので、それが見えないことです。

あなたはこれを難しい方法でやっています。デフォルトの例外ダイアログが気に入った場合は、例外をまったく発生させずに使用してください。

this.BeginInvoke(new Action(() => {
    using (var dlg = new ThreadExceptionDialog(new InvalidOperationException("TEST"))) {
        dlg.ShowDialog();
        Environment.Exit(1);
    }
于 2013-03-29T14:13:26.970 に答える