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

avo*_*avo 108 .net c# 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
        // ...
} 
Run Code Online (Sandbox Code Playgroud)

我可以像这样重写它:

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
        // ...
} 
Run Code Online (Sandbox Code Playgroud)

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

Ste*_*ary 139

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);
}
Run Code Online (Sandbox Code Playgroud)

  • @AlexHopeO'Connor:`Handled` 标志*必须*同步设置;不可能使用 `async` 来决定是否处理事件。 (2认同)
  • @AlexHopeO'Connor:我已经有一段时间没有使用 WPF 应用程序了,但我使用过与过去类似的解决方案。即,使`ICommand.Execute` 方法为`async void`;我认为这是可以接受的,因为`ICommand.Execute` 是*逻辑上* 一个事件处理程序。 (2认同)

Eri*_*ert 45

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

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

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


Ale*_*aum 6

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


Dot*_*mer 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".

这是链接

  • 该链接已损坏,可能已移至此处:https://learn.microsoft.com/en-us/shows/ Three-essential-tips-for-async/tip-1-async-void-top-level-仅事件处理程序 (2认同)