【问题标题】:Why should a void method be async to be able to await?为什么 void 方法应该是异步的才能等待?
【发布时间】:2014-12-03 18:11:33
【问题描述】:

假设我有一个具有void 返回类型的方法,并且我需要await 在此方法中的操作上。

public void someOperation()
{
    //dostuff
    var res = await someOtherOperation();
    //do some other stuff that needs res.
}

当我尝试编译此代码时,我收到错误消息说someOperation 必须声明async。我不明白为什么。我理解如果该方法有返回值为什么会这样,但当它是void 时就不在这里了。甚至在等待操​​作对方法的返回值没有影响的情况下。
这已作为this 问题的一部分提出,但我没有找到我正在寻找的答案。 This guy 仅提及:

async 关键字启用 await 关键字。所以任何使用等待的方法 必须标记为异步。

  • 首先,我不确定async 关键字启用await 关键字是什么意思。
  • 其次,重申我的问题,我不确定为什么它是必需?

【问题讨论】:

  • 1) 不能在未声明 async 的方法中使用 await 运算符。因此,它启用操作员。 2)我不确定我是否理解您的问题,“为什么需要它?”这是必需的,因为这就是语言的工作方式。究竟是什么问题?
  • 我的意思是,它应该只是为了符合现有设计吗?设计师不想在这种情况下破例?因为从我的角度来看,它不是必需的。该方法可以正常工作,而调用者不需要知道它是async。

标签: c# async-await


【解决方案1】:

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

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

我有一个blog post on the subject,带有指向Eric Lippert's definitive blog post 的链接以及blog comments、Channel9 forums、MSDN forums 中的讨论,当然还有right here on Stack Overflow。

请注意,没有结果值的async 方法的自然 返回类型是Task,而不是void。 void 是 async 方法的非自然返回类型。因此,当您看到“await operator must be within an async method”错误时,您的默认反应应该是将其标记为async 并且将返回类型从void更改为Task:

public async Task someOperationAsync()
{
  //dostuff
  var res = await someOtherOperationAsync();
  //do some other stuff that needs res.
}

这遵循了我的MSDN article on the subject 中的最佳实践之一:避免使用async void。 async void 被语言设计者允许用于事件处理程序(或逻辑上为事件处理程序的代码,例如ICommand.Execute);任何其他用法都会导致问题。

【讨论】:

    【解决方案2】:

    我不明白为什么。

    因为您需要告诉编译器您正在尝试编写异步方法。这正是您引用的文件的意思。

    编译器可以推断您的方法是否包含任何await 表达式 - 但这意味着您可以注释掉方法的一行,整个方法的行为将彻底改变。 (想想异常处理,例如......)

    它还提高了可读性 - 这意味着任何阅读您的代码的人都知道这是一个异步方法。

    所以基本上,答案是:

    • 您需要这样做,因为语言规范要求您这样做。编译器正在实现语言规范。
    • 语言规范要求您这样做,因为它减少了意外因素。

    【讨论】:

    • 乔恩,有这个副本吗?如果没有,那么这可能会成为规范的“为什么我需要让我的方法async”问题。
    • @JohnSaunders:不是我知道的副手。可能有,但我现在不知道 :)
    • @JohnSaunders 在我看来,这个问题的规范参考是Eric's blog post。它包括对 Jon 在这里总结的要点的更深入的探索,以及其他一些内容,例如避免破坏性更改(如果有人有一个名为 await pre-5.0 的方法呢?)。
    【解决方案3】:

    因为它们必须在 C# 中成对工作。这是规矩。

    “async”关键字在该方法中启用“await”关键字并更改方法结果的处理方式。这就是 async 关键字的全部作用!它不会在线程池线程上运行此方法,也不会执行任何其他类型的魔法。 async 关键字只启用 await 关键字(并管理方法结果)。

    【讨论】:

      猜你喜欢
      • 2023-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      • 2019-01-28
      • 1970-01-01
      • 2017-03-21
      相关资源
      最近更新 更多