虽然我已经在某种程度上理解了使用C#进行异步编程,但我仍然不明白为什么异步void不是更好的解决方案。当我想要改进我的Xamarin Forms代码时,我发现许多MVVM框架使用AsyncCommand来避免void与async的结合,“不同于事件”的写法如下所示:
public class AsyncCommand : Command {
public AsyncCommand(Func<Task> execute) : base(() => execute()) { }
public AsyncCommand(Func<object, Task> execute) : base((arg) => execute(arg)) { }
}
但我不知道为什么异步命令本身不是异步的,如果使用异步命令并运行类似这样的任务会怎样:
public AsyncCommand(Action execute) : this(() => Task.Run(execute))
public AsyncCommand(Action<object> execute) : this((arg) => Task.Run(() => execute(arg)))
ICommandSource
在操作一个ICommand
上,而ICommand
只定义了同步的ICommand.Execute
方法。除非你在自己的代码中执行AsyncCommand
,否则ICommandSource
(例如一个Button
)不会等待任何东西,它会同步调用ICommand.Execute
。这与将异步 lambda 分配给Action
委托具有相同的效果:lambda 也不会被等待。在这两种情况下,等待链都被打断了。因此,从Button
的角度来看,你的命令处理程序是async void
还是async Task
都无关紧要。 - user21970328IAsyncCommandSource
并重构他们的ICommandSource
实现以支持IAsyncCommandSource
(例如,使Button
调用await this.Command.ExecuteAsync
),否则只有自定义的ICommandSource
实现和能够显式调用和等待IAsyncCommand.ExecuteAsync
的自定义代码才会受益。 - user21970328