繁体   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