如何在父方法中等待没有async修饰符的async方法?

本文关键字:方法 async 等待 | 更新日期: 2023-09-27 18:16:20

我有一个方法,我想等待,但我不想引起多米诺骨牌效应,认为任何东西都可以调用这个调用方法并等待它。例如,我有这个方法:

public bool Save(string data)
{
   int rowsAffected = await UpdateDataAsync(data);
   return rowsAffected > 0;
}

我打电话:

public Task<int> UpdateDataAsync()
{
  return Task.Run(() =>
  {
    return Data.Update(); //return an integer of rowsAffected
  }
}

这将不起作用,因为我必须将"async"放在Save()的方法签名中,然后我不能返回bool,我必须使其成为Task<bool>,但我不希望任何人等待Save()方法。

是否有一种方法可以暂停代码执行,如等待或以某种方式等待此代码没有异步修饰符?

如何在父方法中等待没有async修饰符的async方法?

我怎么能等待一个async方法没有async修饰符在这个父方法?

这有点像问"我如何使用c#编写应用程序,而不依赖于任何类型的。net运行时?"

简短的回答:不要那样做。

实际上,您在这里所做的是采用自然同步方法(Update),通过在线程池线程(UpdateDataAsync)上运行它使其看起来是异步的,然后您想要阻塞它以使异步方法看起来是同步的(Save)。严重的危险信号。

我建议您仔细研究Stephen Toub的两篇著名的博客文章:我是否应该为我的同步方法公开异步包装器,以及我是否应该为我的异步方法公开同步包装器。这两个问题的答案都是"不",尽管Stephen Toub解释了几个选项,如果你真的必须这样做。

"真的必须"应该保留给应用程序级别。我假设这些方法(UpdateUpdateDataAsyncSave)位于应用程序的不同层(例如,数据/数据服务/视图模型)。数据/数据服务层不应该进行同步/异步转换。视图模型(特定于应用程序)级别是唯一一个有理由进行这种转换的级别——而且它应该只在最后才这样做。

编辑:这个答案是在任务之前。增加了Run。有了这个额外的上下文,这个场景最好被描述为"不要那样做"。


您可以访问.Result或使用.Wait(),但您需要首先知道任务是如何实现的。特别是,您需要知道它是否使用同步上下文。这很重要的原因是,如果它这样做,可能会立即死锁,因为一些同步上下文需要调用上下文完全退出(例如,MVC的同步上下文需要离开控制器的动作方法)。

要防止这种情况是很难的,但您可能应该始终通过调用.Wait()显式地指定超时-以防万一。