Как поместить асинхронный метод в список и вызывать их итеративно? - PullRequest
0 голосов
/ 16 января 2019

В последнее время я хочу реализовать проверку работоспособности для списка сервисных вызовов. Все они асинхронные задачи (например, Task<IHttpOperationResponse<XXX_Model>> method_name(...)

Я бы хотел поместить их всех в список. Я последовал за ответом этого поста: Хранение списка методов в C # Однако они являются асинхронными методами.

Я сказал это так: коллекция асинхронных методов

List<Action> _functions = new List<Action> {
      () => accountDetailsServiceProvider.GetEmployer(EmployerId),                                  
      () => accountServiceProvider.GetAccountStatus(EmployerId)
}

Может кто-нибудь направить меня к правильному способу размещения асинхронных методов в списке и итеративного их вызова?

Заранее спасибо!

Ответы [ 3 ]

0 голосов
/ 16 января 2019

Я думаю, вы просто ищете что-то простое?

var myList = new List<Action>()
{
    async() => { await Foo.GetBarAsync(); },
    ...
};

Я бы порекомендовал вам изменить тип с Action на Func<Task>, например, так.

var myList = new List<Func<Task>>()
{
  async() => { await Foo.GetBarAsync(); },
};

Подробнее о причинах вы можете прочитать здесь: https://blogs.msdn.microsoft.com/pfxteam/2012/02/08/potential-pitfalls-to-avoid-when-passing-around-async-lambdas/

Для вызова (упрощенно)

foreach (var action in myList)
{
    await action.Invoke();
}
0 голосов
/ 16 января 2019

Основано на комментариях:

Тем не менее, моя задача требует логического значения для каждого вызова метода, потому что я должен сообщить о состоянии переднего услуга не работает или нет

Создать метод-обертку для метода, который будет возвращать требуемое логическое значение

public async Task<Result> Check(string name, Func<Task> execute)
{
    try
    {
        await execute();
        return new Result(name, true, string.Empty);
    }
    catch (Exception ex)
    {
        return new Result(name, false, ex.Message);
    }
}

public class Result
{
    public string Name { get; }
    public bool Success { get; }
    public string Message { get; }
    public Result(string name, bool success, string message) 
        => (Name, Success, Message) = (name, success, message);
}

Тогда вам не нужно иметь коллекцию делегатов, вместо этого у вас будет коллекция Task.

var tasks = new[]
{
    Check(nameof(details.GetEmployer), () => details.GetEmployer(Id)),
    Check(nameof(accounts.GetAccountStatus), () => accounts.GetAccountStatus(Id)),
};

var completed = await Task.WhenAll(tasks);

foreach (var task in completed)
{
    Console.WriteLine($"Task: {task.Name}, Success: {task.Success};");
}
0 голосов
/ 16 января 2019

Во-первых, вам нужно сделать ваши методы асинхронными. Это означает, что они должны вернуть задание. Например:

public static async Task Foo()
{
    await Task.Delay(1);
    Console.WriteLine("Foo!");
}

public static async Task Bar()
{
    await Task.Delay(1);
    Console.WriteLine("Bar!");
}

Затем, чтобы поместить их в список, вы должны определить список как содержащий правильный тип. Поскольку асинхронный метод на самом деле что-то возвращает, это Func, а не действие. Возвращает задание.

var actions = new List<Func<Task>>
{
    Foo, Bar
};

Чтобы вызвать их, выберите над списком (используя Linq), чтобы вызвать их. Это создает список задач вместо списка функций.

var tasks = actions.Select( x => x() );

Тогда просто жди их:

await Task.WhenAll(tasks);

Полный пример:

public static async Task MainAsync()
{
    var actions = new List<Func<Task>>
    {
        Foo, Bar
    };
    var tasks = actions.Select( x => x() );
    await Task.WhenAll(tasks);
}

Выход:

Foo!
Bar!

Пример для DotNetFiddle

Если ваши методы возвращают логическое значение, , тогда тип возвращаемого значения становится Task<bool>, а остальные следуют его примеру:

public static async Task<bool> Foo()
{
    await Task.Delay(1);
    Console.WriteLine("Foo!");
    return true;
}

public static async Task<bool> Bar()
{
    await Task.Delay(1);
    Console.WriteLine("Bar!");
    return true;
}

var actions = new List<Func<Task<bool>>>
{
    Foo, Bar
};

var tasks = actions.Select( x => x() );

await Task.WhenAll(tasks);

После того, как вы ожидаете их, вы можете преобразовать задачи в их результаты с помощью еще одного оператора LINQ:

List<bool> results = tasks.Select( task => task.Result ).ToList();
...