14

これが私の仮定の例です。ボタンが1つ付いた非常に単純なWPFウィンドウがあります。 Button.Clickイベントには、このようなハンドラがあります。

Action doit = () =>
{
    Action error = () => { throw new InvalidOperationException("test"); };

    try {
        this.Dispatcher.Invoke(error, DispatcherPriority.Normal);
    } catch (Exception ex) {
        System.Diagnostics.Trace.WriteLine(ex);
        throw;
    }
};
doit.BeginInvoke(null, null);

私は例外がキャッチされて、それによって書き留められることを期待するでしょうTrace.WriteLineコール。代わりに、例外はキャッチされず、アプリケーションは中断します。

誰かがこれが起こる可能性のある説明を知っていますか?とによって呼び出されたデリゲートによってスローされた例外をキャッチするためにどのような回避策を提案しますかDispatcher.Invoke

更新1:入れますthrow例外処理コードで。私は実際に例外を無視したくありません。私の質問の全てのポイントはそれを正しく扱うことです。問題は、例外処理コードが実行されないことです。

これは架空の例です。私の本当のコードはそのようには見えません。また、呼び出されるメソッド内のコードを変更できないとします。

更新2:この同様の例を考えてください。 WPFウィンドウの代わりに、Windowsフォームウィンドウがあります。それはほぼ正確に同じハンドラを持つボタンを持っています。唯一の違いは呼び出しコードにあります。こんなふうになります。

this.Invoke(error);

Windowsフォームでは、例外処理コードが実行されます。なぜ違いがありますか?

1 답변


5

更新しました:他のスレッドの例外を観察するには、Task、それをキューに入れるDispatcherスレッド(TaskScheduler.FromCurrentSynchronizationContextそして、それを待ってください。

var ui = TaskScheduler.FromCurrentSynchronizationContext();
Action doit = () => 
{ 
    var error = Task.Factory.StartNew(
        () => { throw new InvalidOperationException("test"); },
        CancellationToken.None,
        TaskCreationOptions.None,
        ui); 

    try { 
        error.Wait(); 
    } catch (Exception ex) { 
        System.Diagnostics.Trace.WriteLine(ex); 
    } 
}; 
doit.BeginInvoke(null, null); 

更新された(再び):あなたの目標は再利用可能なコンポーネントなので、私はTaskベースのインターフェースまたは他のものに基づくものSynchronizationContextのようなイベントベースの非同期パターンコンポーネントをベースにする代わりに、DispatcherまたはISynchronizeInvoke

DispatcherベースのコンポーネントはWPF / Silverlightでのみ機能します。ISynchronizeInvokeベースのコンポーネントはWindowsフォームでのみ機能します。SynchronizationContextベースのコンポーネントは、WPFやWindowsフォーム、そして(もう少し手を加えて)ASP.NET、コンソールアプリケーション、ウィンドウサービスなどと透過的に動作します。

イベントベースの非同期パターンは、古いお勧めの書き方です。SynchronizationContextベースのコンポーネント.NET 3.5時代のコードではまだ出回っています。 .NET 4を使用している場合は、タスク並列ライブラリのほうがはるかに柔軟でクリーン、そして強力です。のTaskScheduler.FromCurrentSynchronizationContext用途SynchronizationContextこのような同期を必要とする再利用可能なコンポーネントを書くための新しい方法です。


  • 捕捉された例外を処理する方法は関係ありません。私はいくらかのログ記録を置くことができるか、あるいは何でもそこに置くことができます。問題は、例外処理コードが実行されないことです。 - jpbochi
  • これは、例外が別のスレッドでスローされたためです。Dispatcher糸。 - Stephen Cleary
  • @スティープン:私はそれを知っています。 TargetInvocationExceptionまたはそれに類するものを受け取ることを期待していました。 - jpbochi
  • 例外はスレッド間で自動的に伝播されません。 .NET 4.0を使用したサンプルを投稿しましたTask例外を伝播します。 - Stephen Cleary
  • その場合は、実際にに移行することをお勧めします。Taskベースのインターフェースまたは他のものに基づくものSynchronizationContextのようなイベントベースの非同期パターン。その理由はSynchronizationContextベースのアプローチは、WPFやWindowsフォーム、そして(もう少し手を加えて)ASP.NET、コンソールアプリケーション、ウィンドウサービスなどを透過的に機能させるでしょう。SynchronizationContext。 - Stephen Cleary

リンクされた質問


関連する質問

最近の質問