Как последовательно выполнить динамический список c асин c функций? - PullRequest
0 голосов
/ 20 января 2020

Я реорганизовал Web API для использования async / await в ASP. NET Core 3.1 и у меня следующий сценарий: метод статистики последовательно вычисляет список индикаторов, которые определены в списке.

readonly Dictionary<StatisticItemEnum, Func<Task<SimpleStatisticItemApiModel>>> simpleItemActionMap =
    new Dictionary<StatisticItemEnum, Func<Task<SimpleStatisticItemApiModel>>>();

private void InitSimpleStatisticFunctionsMap()
{
    simpleItemActionMap.Add(StatisticItemEnum.AllQuestionCount, GetAllQuestionCountApiModel);
    simpleItemActionMap.Add(StatisticItemEnum.AllAnswerCount, GetAllAnswerCountApiModel);
    simpleItemActionMap.Add(StatisticItemEnum.AverageAnswer, GetAverageAnswer);
    // other mappings here
}

private async Task<SimpleStatisticItemApiModel> GetAllQuestionCountApiModel()
{
    // await for database operation
}

private async Task<SimpleStatisticItemApiModel> GetAllAnswerCountApiModel()
{
    // await for database operation
}

private async Task<SimpleStatisticItemApiModel> GetAverageAnswer()
{
    // await for database operation
}

Код последовательно проходит через каждый элемент и вычисляет его, и после рефакторинга он выглядит следующим образом:

itemIds.ForEach(itemId =>
{
    var itemEnumValue = (StatisticItemEnum) itemId;
    if (simpleItemActionMap.ContainsKey(itemEnumValue))
    {
        var result = simpleItemActionMap[itemEnumValue]().Result;
        payload.SimpleStatisticItemModels.Add(result);
    }
}); 

Я знаю, что Task.Result может привести к тупикам , но я не смог найти другого способа заставить эту работу.

Вопрос: Как выполнить динамический c список асинхронных c функций последовательно

Ответы [ 2 ]

1 голос
/ 20 января 2020

Вы должны изменить ForEach на обычный foreach, и тогда вы можете использовать await:

foreach (var itemId in itemIds)
{
  var itemEnumValue = (StatisticItemEnum) itemId;
  if (simpleItemActionMap.ContainsKey(itemEnumValue))
  {
    var result = await simpleItemActionMap[itemEnumValue]();
    payload.SimpleStatisticItemModels.Add(result);
  }
}

Не делайте ForEach лямбда async; это приведет к методу async void, и вам следует избегать async void.

0 голосов
/ 20 января 2020

Я думаю, вы можете сделать это:

itemIds.ForEach(async itemId =>
{
    var itemEnumValue = (StatisticItemEnum) itemId;
    if (simpleItemActionMap.ContainsKey(itemEnumValue))
    {
        var result = await simpleItemActionMap[itemEnumValue]();
        payload.SimpleStatisticItemModels.Add(result);
    }
}); 
...