为什么void方法必须异步才能等待?
假设我有一个具有void
返回类型的方法,并且我需要await
此方法中的操作。
public void someOperation() { //dostuff var res = await someOtherOperation(); //do some other stuff that needs res. }
当我尝试编译此代码时,我得到错误,说someOperation
必须声明为async
。 我不明白为什么。 我理解为什么如果方法有一个返回值,但是当它void
时不会出现。 甚至在等待操作对方法的返回值没有影响的情况下。
这已经被问到这个问题的一部分,但我找不到我想要的答案。 这家伙只是提到:
async关键字启用await关键字。 因此,任何使用await的方法都必须标记为异步。
- 首先,我不确定
async
关键字启用await
关键字是什么意思。 - 其次,重申我的问题,我不确定为什么需要它?
必须将异步方法标记为async
。 async
和await
关键字配对在一起,主要是出于向后兼容的原因; await
是一个有效的标识符(不是关键字),因此当它添加到语言中时,它们还添加了async
关键字。
或者,他们可以使用多字关键字进行await
,例如await for
。 然而,语言设计团队决定采用配对,因为它清楚明确地标记了所有async
方法 – 编译器和人类都更容易解析。
我有关于这个主题的博客文章 ,链接到Eric Lippert的 权威 博客文章以及博客评论 , Channel9论坛 , MSDN论坛的讨论 ,当然还有Stack Overflow 。
请注意,没有结果值的async
方法的自然返回类型是Task
,而不是void
。 void
是async
方法的非自然返回类型。 因此,当看到“await运算符必须在异步方法中”错误时,您的默认反应应该是将其标记为async
并将返回类型从void
更改为Task
:
public async Task someOperationAsync() { //dostuff var res = await someOtherOperationAsync(); //do some other stuff that needs res. }
这遵循我的MSDN文章中关于该主题的最佳实践之一:避免async void
。 语言设计者允许 async void
用于事件处理程序(或逻辑上是事件处理程序的代码,如ICommand.Execute
); 任何其他用法都会导致问题。
我不明白为什么。
因为您需要告诉编译器您正在尝试编写异步方法。 这正是你引用的文件意味着什么。
编译器可以推断出你的方法是否包含任何await
表达式 – 但这意味着你可以注释掉一个方法的一行,整个方法的行为会发生根本改变。 (考虑例外处理,例如…)
它还提高了可读性 – 这意味着任何读取代码的人都知道这是一种异步方法。
所以基本上,答案是:
- 您需要,因为语言规范要求您。 编译器正在实现语言规范。
- 语言规范要求你,因为它减少了惊喜的元素。
因为它们必须在C#中成对使用。 这是规则。
“async”关键字在该方法中启用“await”关键字,并更改方法结果的处理方式。 这就是async关键字的作用! 它不会在线程池线程上运行此方法,也不会执行任何其他类型的魔术。 async关键字仅启用await关键字(并管理方法结果)。