在NotifyTaskCompletion场景中,丢弃返回Task与async void方法有何差异?
关于NotifyTaskCompletion中WatchTaskAsync的async void与Task丢弃问题
一、改成async void的核心区别
- 异常处理逻辑完全不同:async void是专门为事件处理器设计的语法,它抛出的未捕获异常会直接抛到当前线程的同步上下文(比如UI线程),大概率导致应用崩溃。而async Task的异常会被封装在返回的Task对象中,就算你丢弃这个Task,只要方法内部用await处理了异步操作(比如WatchTaskAsync里await传入的Task),异常会被捕获到Task里,不会直接炸掉UI。Stephen Cleary的实现里肯定会把异常赋值给NotifyTaskCompletion的Error属性,改成async void的话,一旦内部出现未处理异常,直接就崩了。
- 可维护性差:async void方法无法被等待,也没法被其他异步方法组合,以后如果需求变了要等待这个监控操作完成,根本没法改。而且调试时,async Task的异步流程能被追踪,async void的则不行,出问题很难排查。
- 上下文恢复风险:虽然async void也会恢复上下文,但在某些复杂嵌套异步的场景下,可能会出现上下文混乱的情况,而async Task的上下文处理更可靠。
二、创建Task后直接丢弃是否合理?
在这个场景下是合理的,原因如下:
- WatchTaskAsync的核心作用是后台监控传入的Task状态,同步更新ViewModel的属性(比如IsCompleted、Error等),调用者(ViewModel初始化代码)不需要等待这个监控完成,只需要它在后台自动完成状态同步就行。
- 关键前提:Stephen Cleary的实现里,WatchTaskAsync内部已经正确处理了所有异常——它会await传入的Task,把异常捕获后赋值给NotifyTaskCompletion的Error属性,不会让异常泄漏出来。所以就算丢弃返回的Task,也不会有未处理异常的问题。
- 如果你不创建这个Task,反而没法启动这个后台监控流程,因为异步方法只有被调用才会开始执行。
当然要注意:如果是你自己写类似的方法,一定要确保内部处理了所有异常,不然丢弃Task会导致异常被“吞掉”(或者在垃圾回收时抛出,引发崩溃)。
内容的提问来源于stack exchange,提问作者LWChris
相关产品推荐
相关产品推荐

