我应该避免'async void'事件处理程序吗?

时间:2013-10-16 23:21:03

标签: c# .net events asynchronous async-await

我知道使用fire-and-forget 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
        // ...
} 

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

4 个答案:

答案 0 :(得分:129)

指南是在事件处理程序中使用时避免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);
}

答案 1 :(得分:41)

  

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

通常事件处理程序是一种情况,其中void async方法不是潜在的代码气味。

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

答案 2 :(得分:5)

是的,通常async 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".

这是link

答案 3 :(得分:3)

如果您使用ReSharper,免费的ReCommended Extension可能会对您有所帮助。它分析了“异步空白”方法,并在不恰当地使用时突出显示。 扩展可以区分异步void的不同用法,并提供此处描述的适当快速修复:ReCommended-Extension wiki