通过等待每个任务异步转换IEnumerable <Task <T >>

Gam*_*ing 20 c# linq task-parallel-library async-await

今天我想知道如何通过等待每个任务来转换任务列表.请考虑以下示例:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我想在没有foreach的情况下转换我的任务列表,但是匿名函数语法和通常的函数语法都允许我做我的foreach所做的事情.

我是否必须依靠我的foreach和List<T>或者有什么办法让它与它一起工作IEnumerable<T>及其所有优点?

Ton*_*ina 35

那这个呢:

await Task.WhenAll(tasks1);
var gainStrings = tasks1.Select(t => t.Result).ToList();
Run Code Online (Sandbox Code Playgroud)

等待所有任务结束,然后提取结果.如果您不关心它们的完成顺序,这是理想的选择.

编辑2:更好的方式:

var gainStrings = await Task.WhenAll(tasks1);
Run Code Online (Sandbox Code Playgroud)

  • [都能跟得上](http://msdn.microsoft.com/en-us/library/hh194766.aspx).即使传入一个`IEnumerable <Task <TResult >>`,它也会返回一个结果数组 (4认同)
  • 您可以只使用`WhenAll`的返回值,而不是`Select`,它将是每个任务的所有结果的`string []`. (3认同)
  • 你不需要`ToArray()`,`Task.WhenAll()`也适用于`IEnumerable <Task <T >>`. (3认同)