我应该避免“异步 void”事件处理程序吗?

我知道通常认为使用启动和忘记 async void方法来启动任务是一个坏主意,因为没有挂起任务的跟踪,并且处理可能在这种方法中抛出的异常非常棘手。

我一般是否也应该避免使用 async void事件处理程序? 例如,

private async void Form_Load(object sender, System.EventArgs e)
{
await Task.Delay(2000); // do async work
// ...
}

我可以这样重写:

Task onFormLoadTask = null; // track the task, can implement cancellation


private void Form_Load(object sender, System.EventArgs e)
{
this.onFormLoadTask = OnFormLoadTaskAsync(sender, e);
}


private async Task OnFormLoadTaskAsync(object sender, System.EventArgs e)
{
await Task.Delay(2000); // do async work
// ...
}

除了可能的重入之外,异步事件处理程序的水下岩石是什么?

56248 次浏览

我一般是否也应该避免使用异步 void 事件处理程序?

通常情况下,事件处理程序是 void 异步方法不具有潜在代码味道的情况。

现在,如果出于某种原因你确实需要跟踪任务,那么你所描述的技术是完全合理的。

指导原则是在事件处理程序中使用时避免使用 async void 除了,因此在事件处理程序中使用 async void是可以的。

也就是说,由于 单元测试的原因,我经常喜欢分解出所有 async void方法的逻辑,

public async Task OnFormLoadAsync(object sender, EventArgs e)
{
await Task.Delay(2000);
...
}


private async void Form_Load(object sender, EventArgs e)
{
await OnFormLoadAsync(sender, e);
}

是的,事件处理程序的异步 void 通常是唯一的情况。如果你想知道更多,你可以在第9频道看到一个很棒的视频

The only case where this kind of fire-and-forget is appropriate is in top-level event-handlers. Every other async method in your code should return "async Task".

这是 链接

如果您使用 ReSharper,一个免费的 建议延期可能会对您有所帮助。它分析了“异步 void”方法,并在使用不当时突出显示。 该扩展可以区分异步 void 的不同用法,并提供适当的快速修复: 推荐-扩展维基