在我的UWP应用程序中,我需要从另一个线程更新UI,我正在使用CoreDispatcher来执行此操作。我希望任何未处理的异常终止应用程序,就像UI线程中的异常一样,但似乎并非如此。下面的RunAsync lambda中抛出的异常将被UWP静默忽略。此外,这些异常永远不会发送到任何应用程序UnhandledException处理程序(以下示例中的第二个例外)。
发生了什么事? Dispatcher是否只捕获所有异常并默默忽略它们?
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
var dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
Task.Run( async () =>
{
await Task.Delay(2000);
await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
throw new Exception("This exception will not terminate the app.");
});
});
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
throw new NotImplementedException("This will terminate the app");
}
}
答案 0 :(得分:3)
它们在技术上不是无法处理的,因为任务中的异常被“捕获”并包装在Task对象中。如果没有以某种方式从该任务中消耗该异常(通过等待任务或使用.ContinueWith),当任务被垃圾收集时,您可以监听TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
以获取该异常 - 您可以手动终止该应用程序如果你愿意或重新抛出,那就从那里开始。
当然要记住,根据你编写代码的方式,不能保证任务会被任何急速垃圾收集,或者根本不可能 - 所以如果你在任何地方存储对任务的引用,那么很可能如果你不小心的话,默默地吞下这些例外。
答案 1 :(得分:1)
发生了什么事? Dispatcher是否只捕获所有异常并默默忽略它们?
不是Dispatcher
问题。问题是当运行Task
时,它抛出的任何异常都会在任务完成时保留并重新抛出。因此,如果您想要终止应用程序的异常,则需要等待Task
完成。
目前,您可以使用await
关键字等待任务变为现在。
private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
await Task.Run(async () =>
{
await Task.Delay(2000);
await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
throw new NotImplementedException("This exception also terminate the app.");
});
});
}
答案 2 :(得分:0)
要处理来自其他线程的错误,只需使用ContinueWith
函数即可。您的代码可以是:
Task.Run(async () =>
{
await Task.Delay(2000);
throw new Exception("This exception will terminate the app.");
})
.ContinueWith(async (res) =>
{
if (res.IsFaulted)
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() => throw res.Exception.InnerException);
});