传播的异步/等待方法调用

时间:2014-10-19 10:12:33

标签: c# .net asynchronous

所以我在我的基本控制器中有这个方法:

protected async Task<KeyValuePair<bool, string>> ExecuteSimpleQuery(Func<Task<bool>> service)
{
    var success = false;
    var message = string.Empty;

    try
    {
        success = await service.Invoke();
    }
    catch (Exception exception)
    {
        message = exception.Message;
        success = false;
    }

    return new KeyValuePair<bool, string>(success, message);
}

我想这样用:

public async Task<ActionResult> Login(RegisterDto register)
{
    var objectStore =
        await this.ExecuteSimpleQuery(async () => await this.securityService.LoginAsync(register.UserName, register.Password, true));

    if (objectStore.Key)
    {
        return this.RedirectToAction("Index", "Toolbox");
    }

    this.TempData["error"] = objectStore.Value;
    return this.View(register);
}

所以我传递给ExecuteSimpleQuery的是awaitable方法LoginAsync,我只是想确保我正在等待该方法。

我的思维过程是:

  1. LoginAsync会返回Task<bool>,因此Func必须返回该内容。
  2. 传递时,您可以await,也可以。
  3. 由于FuncTask<bool>内返回ExecuteSimpleQuery,您可以await在那里,所以应该
  4. ExecuteSimpleQuery正在等待某个方法,因此必须拥有async关键字,因此必须返回Task<T>
  5. 最后一点传播到Login操作,该方法返回Task<T>,因此可以等待它。
  6. 我甚至关闭了吗?

1 个答案:

答案 0 :(得分:2)

这会奏效。它可以简化一点:

async () => await this.securityService.LoginAsync(register.UserName, register.Password, true)

可以写成

() => this.securityService.LoginAsync(register.UserName, register.Password, true)

因为LoginAsync已经返回Task。这就是说,每当你处理任务时总是在等待它们具有一定的一致性。以你的方式包装这个任务并不是真的有害。我认为两种方式都是合理的。

如果LoginAsync无法抛出任何异常(您关心的话),则根本不需要lambda。当您调用异步方法时,异常通常存储在Task中。您可以直接将Task传递给ExecuteSimpleQuery。如果LoginAsync不符合此模式,则无法执行此操作,因为异常会过早触发。

   var loginTask = securityService.LoginAsync(register.UserName, register.Password, true);
   var objectStore = await ExecuteSimpleQuery(loginTask);

protected async Task<KeyValuePair<bool, string>> ExecuteSimpleQuery(Task<bool> service)
{
    //...

    try
    {
        success = await service;
    }
    catch (Exception exception)
    {
        //...
    }

    //...
}

您可以通过说:

来测试
   var loginTask = Task.Run(() => { throw null; });

catch会被点击。