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