在 C# 中,await 运算符是否仅限用于返回 Task 类型的方法?请解释其背后的原理。
考察说明
考查对 await 运算符适用对象的理解,及其与可等待模式的关系。
回答思路
- 【回答框架 1】await 运算符并不要求方法必须返回 Task。其核心要求是操作数必须是可等待的,即实现了 GetAwaiter 方法并返回符合模式的对象,该对象需具备 IsCompleted 属性、GetResult 方法和 INotifyCompletion 接口。
- 【回答框架 2】因此,只要类型提供了必要的等待模式成员,await 就可以用于任何返回该类型的表达式。常见的 Task 和 Task<T> 只是实现该模式的内置类型,但自定义类型也可以被 await。
- 【回答框架 3】在异步方法中,编译器会将 await 转换为状态机,通过检查操作数的 GetAwaiter 方法来生成相应的续延代码。如果类型不满足模式,则会在编译时报错。
- 【回答框架 4】实际使用时,异步方法可以返回 void、Task 或 ValueTask,这些类型本身不是 await 操作数的必要条件,但通常作为异步操作的返回类型。
- 【关键点 1】await 的操作数需实现可等待模式,而非限于 Task 类型。
- 【关键点 2】可等待模式要求 GetAwaiter、IsCompleted、GetResult 和 INotifyCompletion。
- 【关键点 3】编译器通过状态机转换实现异步续延。
- 【关键点 4】自定义类型可实现该模式以支持 await。