在WPF应用中,我添加了两个按钮,一个按钮启动一个Task,另一个按钮强制GC运行:
private void Button_Click(object sender, RoutedEventArgs e)
{
Task.Run(() =>
{
throw new Exception("Some Exception");
});
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
任务只是引发异常。
在Release config中运行该应用程序时,我先按第一个按钮,然后按第二个按钮,并期望该应用程序崩溃。无论我按几次按钮,都不会发生这种情况。
我知道.NET 4.5中存在无法观察的任务吞没异常的行为:https://blogs.msdn.microsoft.com/pfxteam/2011/09/28/task-exception-handling-in-net-4-5/
但是我感到困惑的是,为什么一旦GC运行,应用程序就不会崩溃。根据我的理解,一旦任务被收集,就应该抛出信号。
还请注意,我知道这个问题无法回答我的问题 Why doesn't my process terminate when Task has unhandled exception?
标记为答案的评论建议使用ContinueWith
,但这也不起作用,应用程序也不会崩溃,但吞没了异常:
private void Button_Click(object sender, RoutedEventArgs e)
{
Task.Run(() =>
{
throw new Exception("Some Exception");
}).ContinueWith(t =>
{
if (t.IsFaulted) { throw t.Exception.InnerException; }
});
}
我已经知道等待任务会导致应用崩溃。
答案 0 :(得分:5)
这是因为您开枪而忘记了。异常将在单独的线程中发生。如果您希望它崩溃,则必须await
或使其同步。
private void Button_Click(object sender, RoutedEventArgs e)
{
await Task.Run(() =>
{
throw new Exception("Some Exception");
});
}
答案 1 :(得分:4)
但是我感到困惑的是,为什么一旦GC运行,应用程序就不会崩溃。根据我的理解,一旦任务被收集,就应该抛出信号。
您的理解是正确的,前提是您通过在1
中添加以下元素来使用旧的行为(.NET Framework 4.5之前的版本):
Foo::where('bar', function($query) {
$query->fromBaz(1);
});
如果您不这样做,App.config
将不会导致进程崩溃。但是仍然会引发异常,因此您可以在两种情况下都处理<runtime>
<ThrowUnobservedTaskExceptions enabled="true"/>
</runtime>
事件。