将 ICommand 定义为异步 lambda 调用异步任务,还是只是异步无效?
Define ICommand as async lambda calling async Task, or just async void?
考虑以下两种设置 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
.)
As long as one is never calling ToggleCheckedAsync directly, are these two scenarios equivalent, or are there any gotchas with one compared to the other?
两者都可以;它们是等效的方法。 async void
在这里是合适的,因为 ICommand.Execute
在逻辑上是一个事件处理程序。 (不要搞错:在这两种方法中 是 一个 async void
:第一个示例的 lambda 变成 async void
)。
然而,在我自己的代码中,这并不成立:
As long as one is never calling ToggleCheckedAsync directly
特别是单元测试。单元测试可以直接执行你的命令,这包括能够 await
直到它们完成,而 ICommand
不能满足这个需求。
因此,我发现公开 async Task
方法很有用。或者,如果你想变得更高级,开发一个 IAsyncCommand
type with a Task ExecuteAsync
method and expose that from the ViewModel. Taking that design to its logical conclusion, you can end up with a full AsyncCommand
that hides the async void Execute
as an implementation detail.
考虑以下两种设置 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
.)
As long as one is never calling ToggleCheckedAsync directly, are these two scenarios equivalent, or are there any gotchas with one compared to the other?
两者都可以;它们是等效的方法。 async void
在这里是合适的,因为 ICommand.Execute
在逻辑上是一个事件处理程序。 (不要搞错:在这两种方法中 是 一个 async void
:第一个示例的 lambda 变成 async void
)。
然而,在我自己的代码中,这并不成立:
As long as one is never calling ToggleCheckedAsync directly
特别是单元测试。单元测试可以直接执行你的命令,这包括能够 await
直到它们完成,而 ICommand
不能满足这个需求。
因此,我发现公开 async Task
方法很有用。或者,如果你想变得更高级,开发一个 IAsyncCommand
type with a Task ExecuteAsync
method and expose that from the ViewModel. Taking that design to its logical conclusion, you can end up with a full AsyncCommand
that hides the async void Execute
as an implementation detail.