为什么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关键字是什么意思。
  • 其次,重申我的问题,我不确定为什么需要它?

必须将异步方法标记为asyncasyncawait关键字配对在一起,主要是出于向后兼容的原因; await是一个有效的标识符(不是关键字),因此当它添加到语言中时,它们还添加了async关键字。

或者,他们可以使用多字关键字进行await ,例如await for 。 然而,语言设计团队决定采用配对,因为它清楚明确地标记了所有async方法 – 编译器和人类都更容易解析。

我有关于这个主题的博客文章 ,链接到Eric Lippert的 权威 博客文章以及博客评论 , Channel9论坛 , MSDN论坛的讨论 ,当然还有Stack Overflow 。

请注意,没有结果值的async方法的自然返回类型是Task ,而不是voidvoidasync方法的非自然返回类型。 因此,当看到“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关键字(并管理方法结果)。