考虑以下两种设置ICommand以执行异步任务的方法(在这种情况下,使用Xamarin.Forms.Command
,但我希望这并不重要):
场景1:将命令设置为等待async Task
方法的异步lambda:
// Command definition
ToggleCheckedCommand = new Command(
execute: async () => { await ToggleCheckedAsync(); },
canExecute: () => !IsBusy);
// Method that is executed
private async Task ToggleCheckedAsync()
{
IsBusy = true;
await DoWork();
IsBusy = false;
}
场景2:将命令设置为async void
方法:
// Command definition
ToggleCheckedCommand = new Command(
execute: ToggleCheckedAsync,
canExecute: () => !IsBusy);
// Method that is executed
private async void ToggleCheckedAsync()
{
IsBusy = true;
await DoWork();
IsBusy = false;
}
只要一个人永远不会直接打电话给ToggleCheckedAsync
,这两个场景是否相同,或者是否有任何一个与另一个相比?
(我知道async void
通常被认为是直接事件处理程序之外的不良做法,但ToggleCheckedAsync
在逻辑上是一个事件处理程序,方案1中的异步lambda也是AFAIK有效async void
。)
答案 0 :(得分:3)
只要一个人永远不会直接调用ToggleCheckedAsync,这两个场景是否相同,或者是否有任何一个与另一个相比?
任何一个都没事;他们是等同的方法。 async void
在这里是合适的,因为ICommand.Execute
在逻辑上是一个事件处理程序。 (并且不要搞错:在两种方法中 都是async void
:第一个例子的lambda变为async void
)。
但是,在我自己的代码中,这并不成立:
只要一个人永远不会直接调用ToggleCheckedAsync
特别是单元测试。单元测试可以直接执行您的命令,其中包括能够await
完成命令,ICommand
无法满足此需求。
因此,我发现公开async Task
方法很有用。或者,如果你想获得更高级,请开发IAsyncCommand
type with a Task ExecuteAsync
method and expose that from the ViewModel。将该设计理解为合乎逻辑的结论,您最终可以使用full AsyncCommand
that hides the async void Execute
as an implementation detail。