【问题标题】:How to make C# method async如何使 C# 方法异步
【发布时间】:2013-11-26 21:21:34
【问题描述】:

我在下面有正常的 N 层简化场景:

CONTROLLER 调用 BLL 调用 DAL

在哪里 CONTROLLER有以下方法:

public void WarmUp()
{
    var bll=_bll.WarmUp(ID);
}

BLL 有:

public bool WarmUp()
{
    return_dal.WarmUp(ID);
}

DAL 有:

public bool FetchData()
{
    var dal=_bll.WarmUp(ID);
    if(dal !=null)
     {return true;}
    else{return false;}
}

现在,我喜欢做的是使 BLL 和 DAL 方法(不确定是否都必须是 async)为 ASYNC,以便在 CONTROLLER 调用后,它不会阻塞线程.

我还没有完成基于任务的编程。有人可以帮我将上面的代码(BLL/DLL)转换为异步(c# async await),以便它们是异步的吗?

【问题讨论】:

    标签: c# asynchronous async-await c#-5.0


    【解决方案1】:

    您的 DAL 代码调用 BLL,这是错误的。

    DAL 应该使用数据库调用,这就是您开始的地方。例如。 Entity Framework 支持异步 API,您先调用它们,然后调用 await。这使您的 DAL 方法 async,因此它们的调用者(在 BLL 中)必须 await 他们。这使您的 BLL 方法 async,因此它们的调用者(在“控制器”中)必须 await 他们。这使您的“控制器”方法async

    【讨论】:

      【解决方案2】:

      一般我们可以说,第一个调用方法应该用async标记。在您的情况下,这是控制器中的 WarmUp 方法。

      public async void WarmUp()
      {
          var bll=_bll.WarmUp(ID);
      }
      

      现在我们假设 _bll.WarUp(ID) 是一个长时间运行的方法。所以我们将重构这个方法,让它返回一个Task

      public Task<bool> WarmUp()
      {
          return Task.Run(()=>{_dal.WarmUp(ID);});
      }
      

      但这并不能解决我们的问题,因为现在我们有这样的情况,如果我们调用 Controller 方法,我们将立即返回。如果我们不需要Task的返回值,这没有问题。但是如果我们需要它,我们可以使用await 关键字:

      public async void WarmUp()
      {
          var bll= await _bll.WarmUp(ID);
          if(bll)
          {
              //do whatever you want
          }
      }
      

      【讨论】:

      • 你不应该使用async void方法,除非你必须这样做。
      • 是的,我知道async void 是一个fire and forget 方法,但是我在MVVM 中执行ICommand.Execute 时经常使用它。也许这也不是最好的解决方案?
      【解决方案3】:

      这个怎么样:

      public Task<bool> FetchData()
      {
          var tcs = new TaskCompletionSource<bool>();
          Task.Run(() => {
              var dal=_bll.WarmUp(ID);    
              tcs.SetResult(dal != null);
          });
      
          return tcs.Task.Result;
      }
      

      TaskCompletionSource 有利于使非异步的东西变为可异步的。然后你可以等待调用直到你的最后一层

      public async Task<bool> WarmUp()
      {
          return await _dal.WarmUp(ID);
      }
      

      这可能是您的 GUI 按钮回调。在某些时候,您需要一个 async void 方法,但这是一种即发即弃的方法。除非您有某种事件处理程序,否则应该避免使用。

      public async void WarmUp()
      {
          var bll= await _bll.WarmUp(ID);
      }
      

      【讨论】:

      • TaskCompletionSource 的这种使用没有任何意义。是的,它使方法awaitable,但它不会使其异步。这意味着能够await 完全没用。
      • @svick 你是对的!我已经更新了我的答案以使其异步
      • 好的,如果你使用Task.Run(),为什么不直接返回Task?它更简单,并且可以正确处理异常。
      • 好吧好吧,我同意 TaskCompletionSource 不适合这种情况。例如,如果您调用带有回调的方法,您将使用 TaskCompletionSource。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-12
      • 2021-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-06
      • 1970-01-01
      相关资源
      最近更新 更多