为何TaskAwaiter默认不可被await?添加对应扩展方法是否存在潜在风险?
关于扩展方法的可行性
你写的TaskAwaiter扩展方法确实可以正常运行,不会触发无限循环。
await语法的底层逻辑是只要目标类型存在无参、返回值实现了INotifyCompletion接口的GetAwaiter方法,就可以被await。你给TaskAwaiter扩展的GetAwaiter直接返回自身,而TaskAwaiter本身已经满足awaiter的所有接口要求,编译器只会调用一次GetAwaiter就进入后续的等待逻辑,不会出现反复调用的死循环。
为什么默认没有内置该逻辑
官方没有内置这个实现,核心原因是没有普遍的使用场景。正常开发流程下,开发者都是直接awaitTask/Task<T>实例,完全不会主动获取awaiter之后再await。这种为了绕过静态分析警告的hack属于极其边缘的需求,不可能作为通用语法特性被支持。
存在的风险
这套实现虽然能跑,但有几个明显的问题:
- 本质是绕过静态分析规则的掩耳盗铃行为:VSThreading的警告本意是提醒你不要持有非当前上下文创建的Task,避免出现同步上下文错乱、Task生命周期管理异常等问题,你只是消掉了警告,原本的风险依然存在,后续出相关问题时排查难度会大幅提升
- 兼容性风险:如果后续.NET官方为
TaskAwaiter新增了实例级的GetAwaiter方法,你的扩展方法会被自动覆盖,可能出现行为不符合预期甚至编译失败的问题 - 可维护性差:其他维护人员看到await一个awaiter的写法会非常困惑,需要额外了解你的hack逻辑才能理解代码意图
- 泛型适配问题:你现在写的只是非泛型
TaskAwaiter的扩展,如果要支持带返回值的Task<T>,还需要额外实现TaskAwaiter<T>的对应扩展方法
更合理的绕过方案
如果你确认自己的场景不会触发VSThreading规则对应的风险,更推荐用#pragma warning disable针对性关闭对应警告,或者在分析器配置里给这个扩展方法加排除规则,比修改await的默认行为要安全很多。
内容的提问来源于stack exchange,提问作者cboittin
相关产品推荐
相关产品推荐

