【问题标题】:Should I avoid 'async void' event handlers?我应该避免“异步无效”事件处理程序吗?
【发布时间】:2013-10-25 06:56:42
【问题描述】:

我知道使用即发即弃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
        // ...
} 

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

【问题讨论】:

  • 你应该,但你不能。除此之外,UI 事件处理程序已经需要您在使用 async void 时必须注意的所有事项。
  • 而重入的发生是因为事件处理程序触发的异步操作,而不是单独使用 async-await。

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


【解决方案1】:

指导方针是避免在事件处理程序中使用async voidexcept,因此在事件处理程序中使用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);
}

【讨论】:

  • 我很好奇...您有什么理由不直接更改Form_Loadpublic 的访问权限吗?看起来这样代码会不那么冗长。
  • 哎呀,没关系... Vber 试图在这里阅读 C#... 我刚刚注意到 OnFormLoadAsync 的返回类型。我现在看到这是一个方便的技巧。谢谢。
  • @AlexHopeO'Connor:Handled 标志必须同步设置;无法使用async 来决定是否处理事件。
  • @AlexHopeO'Connor:我已经有一段时间没有使用 WPF 应用程序了,但我使用过与过去类似的解决方案。即,将ICommand.Execute 方法设为async void;我认为这是可以接受的,因为ICommand.Execute 在逻辑上是一个事件处理程序。
  • @NurielZrubavely:如果 catch 子句中有日志记录,它应该在异常时运行。但是,如果您在 ASP.NET 上执行“一劳永逸”,那么任何 async void 方法都可能无法完成。
【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

    是的,通常只有事件处理程序的异步无效是唯一的情况。如果您想了解更多信息,可以在第 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

    【讨论】:

    • 顶级事件处理程序”是一个重要提示。在较低级别的事件处理程序上使用 async void 事件处理程序时,可能会导致未捕获异常的巨大问题。
    • 感谢视频链接,很有用
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 2017-04-16
      • 1970-01-01
      • 2013-01-06
      • 1970-01-01
      • 1970-01-01
      • 2012-10-14
      • 2010-12-30
      • 2021-12-04
      相关资源
      最近更新 更多