Sam*_*Sam 18 .net c# exception task-parallel-library async-await
此代码抛出异常.是否可以定义将捕获它的应用程序全局处理程序?
string x = await DoSomethingAsync();
Run Code Online (Sandbox Code Playgroud)
使用.net 4.5/WPF
nos*_*tio 21
如果我理解正确的话,这实际上是一个很好的问题.我最初投票决定关闭它,但现在撤回了我的投票.
了解async Task
方法内部抛出的异常如何在其外部传播非常重要.最重要的是,需要通过处理任务完成的代码来观察此类异常.
例如,这是一个简单的WPF应用程序,我在.NET 4.5.1上:
using System;
using System.Threading.Tasks;
using System.Windows;
namespace WpfApplication_22369179
{
public partial class MainWindow : Window
{
Task _task;
public MainWindow()
{
InitializeComponent();
AppDomain.CurrentDomain.UnhandledException +=
CurrentDomain_UnhandledException;
TaskScheduler.UnobservedTaskException +=
TaskScheduler_UnobservedTaskException;
_task = DoAsync();
}
async Task DoAsync()
{
await Task.Delay(1000);
MessageBox.Show("Before throwing...");
GCAsync(); // fire-and-forget the GC
throw new ApplicationException("Surprise");
}
async void GCAsync()
{
await Task.Delay(1000);
MessageBox.Show("Before GC...");
// garbage-collect the task without observing its exception
_task = null;
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
}
void TaskScheduler_UnobservedTaskException(object sender,
UnobservedTaskExceptionEventArgs e)
{
MessageBox.Show("TaskScheduler_UnobservedTaskException:" +
e.Exception.Message);
}
void CurrentDomain_UnhandledException(object sender,
UnhandledExceptionEventArgs e)
{
MessageBox.Show("CurrentDomain_UnhandledException:" +
((Exception)e.ExceptionObject).Message);
}
}
}
Run Code Online (Sandbox Code Playgroud)
一旦ApplicationException
抛出,它就不会被观察到.既TaskScheduler_UnobservedTaskException
没有CurrentDomain_UnhandledException
被调用也没有被调用._task
在等待或等待对象之前,异常保持休眠状态.在上面的示例中,它永远不会被观察到,因此TaskScheduler_UnobservedTaskException
仅在任务被垃圾收集时才会被调用.然后吞下这个例外.
AppDomain.CurrentDomain.UnhandledException
可以通过ThrowUnobservedTaskExceptions
在app.config
以下位置配置来启用事件被触发且应用程序崩溃的旧.NET 4.0行为:
<configuration>
<runtime>
<ThrowUnobservedTaskExceptions enabled="true"/>
</runtime>
</configuration>
Run Code Online (Sandbox Code Playgroud)
以这种方式启用时,AppDomain.CurrentDomain.UnhandledException
仍会在异常被垃圾收集后 触发TaskScheduler.UnobservedTaskException
,而不是在抛出的位置触发.
Stephen Toub在他的".NET 4.5中的任务异常处理"博客文章中描述了这种行为.关于任务垃圾收集的部分在帖子的评论中描述.
方法就是这种情况async Task
.对于async void
通常用于事件处理程序的方法,故事情况大不相同.让我们这样改变代码:
public MainWindow()
{
InitializeComponent();
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
this.Loaded += MainWindow_Loaded;
}
async void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
await Task.Delay(1000);
MessageBox.Show("Before throwing...");
throw new ApplicationException("Surprise");
}
Run Code Online (Sandbox Code Playgroud)
因为它async void
没有Task
提到保持(因此没有什么可能被观察或以后垃圾收集).在这种情况下,会立即在当前同步上下文中抛出异常.对于WPF应用程序,Dispatcher.UnhandledException
将首先触发,然后Application.Current.DispatcherUnhandledException
,然后AppDomain.CurrentDomain.UnhandledException
.最后,如果没有处理这些事件(EventArgs.Handled
未设置为true
),则无论ThrowUnobservedTaskExceptions
设置如何,应用程序都将崩溃.TaskScheduler.UnobservedTaskException
是不是在这种情况下被解雇,出于同样的原因:没有Task
.
归档时间: |
|
查看次数: |
3444 次 |
最近记录: |