Подтвердить что ты не робот

Преобразовать IEnumerable <Задача <T>> асинхронно, ожидая каждой задачи

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

private static void Main(string[] args)
{
    try
    {
        Run(args);                
        Console.ReadLine();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
        Console.ReadLine();
    }
}

static async Task Run(string[] args)
{
    //Version 1: does compile, but ugly and List<T> overhead
    var tasks1 = GetTasks();                       

    List<string> gainStrings1 = new List<string>();
    foreach (Task<string> task in tasks1)
    {
        gainStrings1.Add(await task);
    }
    Console.WriteLine(string.Join("", gainStrings1));

    //Version 2: does not compile
    var tasks2 = GetTasks();
    IEnumerable<string> gainStrings2 = tasks2.Select(async t => await t);
    Console.WriteLine(string.Join("", gainStrings2));
}

static IEnumerable<Task<string>> GetTasks()
{
    string[] messages = new[] { "Hello", " ", "async", " ", "World" };

    for (int i = 0; i < messages.Length; i++)
    {
        TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
        tcs.SetResult(messages[i]);
        yield return tcs.Task;
    }
}

Я хотел бы преобразовать свой список задач без foreach, однако либо синтаксис анонимной функции, либо обычный синтаксис функций позволяют мне делать то, что делает мой foreach.

Должен ли я полагаться на свой foreach и List<T> или есть ли способ заставить его работать с IEnumerable<T> и всеми его преимуществами?

4b9b3361

Ответ 1

Как насчет этого:

await Task.WhenAll(tasks1);
var gainStrings = tasks1.Select(t => t.Result).ToList();

Дождитесь завершения всех задач, а затем извлеките результаты. Это идеально, если вам все равно, в каком порядке они закончены.

EDIT2: Еще лучше:

var gainStrings = await Task.WhenAll(tasks1);