async不需要等待的任务方法

时间:2017-09-14 18:31:43

标签: c# async-await

我有一组从基类继承的命令。基类具有以下声明:

public virtual async Task Execute(object parameter){}

继承类提供了此方法的覆盖,并非所有类都等待任务。在这些情况下,编译器会生成警告:

  

这种异步方法缺少'await'运算符并将同步运行。   考虑使用'await'运算符来等待非阻塞API调用,   或'等待Task.Run(...)'在后台线程上进行CPU绑定工作。

明确提供任务完整返回值是否正确?

public override async Task Execute(object parameter) {
    //code containing no await statements...
    await Task.CompletedTask;
}

2 个答案:

答案 0 :(得分:7)

您应该避免在重写方法中使用async关键字,而不是await任何内容,而只是返回Task.CompletedTask

public override Task Execute(object parameter) {
    //code containing no await statements...
    return Task.CompletedTask; // or Task.FromResult(0) for older .NET versions
}

这是(少数)用于此类"模拟"的用例之一。您可以通过looking at this question了解Task.FromResult的任务。这些注意事项仍然适用于Task.CompletedTask

答案 1 :(得分:4)

作为对应点, 处理异常的方式不同。

如果从非async版本的同步代码中引发异常,那么该异常将直接引发给调用者(对于具有异步签名的方法来说非常罕见)。

如果async版本中的同步代码引发异常,则捕获该异常并将其放在返回的任务上(这是具有异步签名的方法的预期行为)。

因此,如果这样调用该方法,则不同的实现将具有不同的异常语义:

var task = Execute(parameter); // non-async exceptions raised here
...
await task; // async exceptions raised here

但是,大多数情况下,该方法被调用并立即等待,因此这两个语义合并在一起:

await Execute(parameter); // both async and non-async exceptions raised here

可能无关紧要,但我相信这是一个值得注意的重要区别。

如果异常语义对您很重要,那么您想要使用async围绕同步代码生成状态机,并且可以在代码中禁用警告:

#pragma warning disable 1998 // use async keyword to capture exceptions
public override async Task Execute(object parameter) {
#pragma warning restore 1998
  //code containing no await statements...
}