142

我知道使用即发即弃的方法来启动任务通常被认为是一个坏主意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

4 回答 4

178

指导方针是避免,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);
}
于 2013-10-16T23:25:38.173 回答
59

我通常也应该避免使用 async void 事件处理程序吗?

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

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

于 2013-10-16T23:25:33.477 回答
7

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

这是链接

于 2014-09-07T06:34:31.740 回答
6

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

于 2016-01-31T00:34:10.947 回答