什么都不做的异步方法

本文关键字:异步方法 什么 | 更新日期: 2023-09-27 18:13:16

我有一个接口IAnimation,它公开了一个方法BeginAsync()。该方法应该启动动画并在动画完成时返回。

我想做的是实现一个null动画类NoAnimation,它只在执行BeginAsync()时返回。

这是正确的实现吗?

public async Task BeginAsync()
{
    await Task.Run(() => { });
}

我怀疑有一种比这更优雅的方法。我也考虑过创建一个空方法。但是这会给我一个警告,我也不喜欢。

什么都不做的异步方法

使用Task.CompletedTask返回一个已完成的任务:

public Task BeginAsync()
{
     return Task.CompletedTask;
}

如果你有一个Task<TResult>,使用Task.FromResult<TResult>返回一个完成的任务,结果:

public Task<bool> BeginAsync()
{
     return Task.FromResult(true);
}

您当前的实现非常低效,因为它构建状态机,并且还使用ThreadPool线程来运行空任务。

我明白这并没有完全回答最初的问题(或者至少不是在另一个答案中没有的方式)。它为@ReedCopsey的答案提供了额外的背景,对于那些人(包括我!)而其他人,根据对这个答案的评论)最初可能很难理解这里发生了什么。


很容易陷入这样的陷阱:认为async必须是任何异步方法签名的一部分。看起来是这样;它(误导!)读起来好像它的全部目的是将一个方法标记为异步。

但它不是,TaskTask<T>是必需的,而不是async。这在@ReedCopsey的答案和下面的正确示例(稍微改编自这个有用的SO答案)中显示:

public Task<int> MethodTaskAsync(int arg0, int arg1)
{
    Task<int> task = new Task<int>(() => Method(arg0, arg1));
    task.Start(); // Hot task (started task) should always be returned.
    return task;
}

这就是为什么接口方法签名不需要,也不能有async关键字:一个"异步"方法本身,不管它是如何实现的,只是一个返回启动(可能已经完成)的TaskTask<T>的方法。

如果async没有将方法标记为异步,它会做什么?这是一种更简单地编写异步方法的方法:一旦你把它应用到一个方法上,你可以使用await关键字来告诉编译器正确地为你处理辅助异步调用,非常简单(没有它,你可以尝试手动处理辅助Task,使用更多类似于上面代码块的代码,但这样做会非常复杂,容易出错)。

因此,如果您只是想从"异步"(即Task返回)方法返回一个什么都不做,已经完成的任务,您可以并且应该同步(!),如在@ReedCopsey的答案中,使用Task.CompletedTaskTask.FromResult(...)