Как использовать async в лямбда, которая возвращает коллекцию

У меня есть метод, который является Async "вверх по течению". Я стараюсь следовать наилучшей практике и идти олл-ин с асинхронным циклом вплоть до стека.

Внутри действия контроллера в MVC я, как ожидается, попал в тупик. Если я полагаюсь на .Result().

Изменение действия контроллера для async похоже на путь, хотя проблема заключается в том, что метод async вызывается несколько раз в lambda.

Как я могу ждать на lamda, которая возвращает несколько результатов?

public async Task<JsonResult>  GetLotsOfStuff()
{
    IEnumerable<ThingDetail> things=  previouslyInitialisedCollection
                                      .Select(async q => await GetDetailAboutTheThing(q.Id)));
    return Json(result, JsonRequestBehavior.AllowGet);

}

Вы можете видеть, что я попытался сделать асинхронный лямбда, но это просто дает исключение для компилятора:

Невозможно преобразовать тип источника

System.Collections.Generic.IEnumerable<System.Threading.Tasks.Task<ThingDetail> для целевого типа System.Collections.Generic.IEnumerable<ThingDetail>

Где я здесь не так?

Ответ 1

  • Преобразуйте коллекцию Thing в коллекцию Task<Thing> s.
  • Затем соедините все эти задачи с помощью Task.WhenAll и ждите его.
  • Ожидая совместной задачи, вы получите Thing[]


public async Task<JsonResult>  GetLotsOfStuff()
{
    IEnumerable<Task<ThingDetail>> tasks = collection.Select(q => GetDetailAboutTheThing(q.Id));

    Task<int[]> jointTask = Task.WhenAll(tasks);

    IEnumerable<ThingDetail> things = await jointTask;

    return Json(things, JsonRequestBehavior.AllowGet);
}

Или, лаконично и используя вывод типа:

public async Task<JsonResult>  GetLotsOfStuff()
{
    var tasks = collection.Select(q => GetDetailAboutTheThing(q.Id));
    var things = await Task.WhenAll(tasks);

    return Json(things, JsonRequestBehavior.AllowGet);
}

Fiddle: https://dotnetfiddle.net/78ApTI

Примечание: поскольку GetDetailAboutTheThing, похоже, возвращает Task<Thing>, соглашение заключается в добавлении Async к его имени - GetDetailAboutTheThingAsync.