簡體   English   中英

捕獲線程中的所有異常

[英]Catching all exception in a thread

假設我有控制台應用程序,並且想在另一個線程中運行WPF Window 到目前為止,這是我的解決方案:

var th = new Thread(() =>
{
    try
    {
        System.Windows.Application currentApp = new System.Windows.Application();
        instance = new App.MainWindow(); //instance is declared somewhere else

        currentApp.Run(instance);
    }
    catch (Exception ex)
    {
        //log exception
    }
});
th.SetApartmentState(ApartmentState.STA);
th.Start();

在代碼的其他地方,我正在更改一些MainWindow屬性,如下所示:

instance.Dispatcher.Invoke(() =>
{
    instance.SomeProperty = "Some value";
});

一切正常,除了例外。 我認為所有的異常將在拋出th線程,該線程內部的的try-catch會趕上他們,但事實並非如此。 如果SomeProperty拋出一個異常,它留下th線程(或從來沒有過吧?),直接出現在我的主線程,導致我的應用程序崩潰/退出。

我究竟做錯了什么? instance.SomeProperty = "Some value"; 不執行上th線程? 我該如何執行它在th線?

WPF提供了一些事件可以幫助您解決問題。 首先,有Application.DispatcherUnhandledException事件

private void App_DispatcherUnhandledException(object sender, 
    DispatcherUnhandledExceptionEventArgs e)
{
    // An unhandled Exception occurred!

    // Prevent default unhandled exception processing
    e.Handled = true;
}

從鏈接頁面:

應用程序針對主UI線程上運行的代碼未處理的每個異常引發DispatcherUnhandledException。

如果在后台用戶界面(UI)線程(具有自己的Dispatcher的線程)或后台工作線程(沒有Dispatcher的線程)上均未處理異常,則該異常不會轉發到主UI線程。 因此,不會引發DispatcherUnhandledException。 在這種情況下,您將需要編寫代碼來執行以下操作:

1.處理后台線程上的異常。

2.將這些異常分配給主UI線程。

3.將它們扔到主UI線程上而不進行處理,以允許引發DispatcherUnhandledException。

您的另一個選項是AppDomain.UnhandledException Event

private void UnhandledExceptions(object sender, UnhandledExceptionEventArgs e)
{
    // An unhandled Exception occurred!
    if (e.IsTerminating)
    {
        // The RunTime is terminating now, so log some error details
    }
}

請注意,此處理程序僅在您收到Exception時為您提供記錄錯誤的方式...該程序將在之后關閉,因此此程序對您而言並不是那么有用。 從MSDN上的鏈接頁面:

此事件提供未捕獲的異常的通知。 它允許應用程序在系統默認處理程序向用戶報告異常並終止應用程序之前記錄有關異常的信息。 如果有足夠的有關應用程序狀態的信息可用,則可以采取其他措施-例如保存程序數據以供以后恢復。 建議小心,因為如果不處理異常,程序數據可能會損壞。

在我提供鏈接的兩頁上,還有很多關於未處理的Exception的文章可供閱讀...您可能做得比徹底閱讀它們還要差。

嘗試使用ContinueWith ,最后嘗試TaskScheduler.FromCurrentSynchronizationContext()方法。 所以你斷言要回到mainThread

Debug.WriteLine("command execute on {0}", Thread.CurrentThread.ManagedThreadId);

Task.Factory.StartNew(() =>
{
   Debug.WriteLine("executing on {0}", Thread.CurrentThread.ManagedThreadId);
   Thread.Sleep(1000);
})
  .ContinueWith(t =>
{
  Debug.WriteLine("task finished on {0}", Thread.CurrentThread.ManagedThreadId);
}, TaskScheduler.FromCurrentSynchronizationContext());

希望會有所幫助。 問候!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM