一个好的一般准则是“避免async void
”。造成这种情况的一个原因是异常处理的差异:async Task
方法会将任何异常放在其返回的 上Task
,这可以在 ed 时观察Task
到await
。方法将直接在方法启动时的当前事件async void
上引发异常。SynchronizationContext
async void
要记住的另一件事是,这async
主要是编译器转换。如果您(或其他任何人)async Task
在运行时反映了一个方法,您只会看到一个返回类型为Task
;的方法。类似地,一个async void
方法只有一个返回类型void
。
因此,当测试运行程序看到一个方法返回void
(不知道它是一个async void
方法)时,它会执行它并看到它返回而没有(直接)引发异常,因此它将其标记为“通过”。同时,该async void
方法抛出的异常直接在SynchronizationContext
(包括 MSTest 在内的大多数测试运行程序提供线程池SynchronizationContext
)上引发,并且此异常可能导致测试运行报告非特定错误 - 或者可能会被忽略,如果测试运行足够快地完成。
现代测试运行器(包括 VS2012 的 MSTest)async Task
通过检测 的返回类型来理解方法,并且在考虑测试方法“完成”并将其标记为通过(或失败,如果返回包含异常)之前Task
将等待完成.Task
Task
我在我的博客上的 MSTest 中有这种行为的示例(包括显示竞争条件的两个输出的屏幕截图),但请注意,这些博客条目已有将近一年的历史,并且谈论async
使用 VS2010 进行单元测试。MSTest 已使用 VS2012 进行了更新,因此它具有合理的async Task
方法行为。