2013-05-02 76 views
14

今天我想知道如何通过等待每个任务来转换任务列表。 请看下面的例子:通过等待每个任务异步地转换IEnumerable <Task<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>及其所有的优点?

+0

为什么第二个不编译?什么是错误信息?如果在'Select'之后添加缺少的'ToList()',它会编译吗? – 2013-05-02 14:23:34

+1

它因为它返回'IEnumerable >'。 – GameScripting 2013-05-02 14:25:52

回答

23

这个怎么样:

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

等待所有任务结束,然后提取结果。如果你不关心他们完成的顺序,这是理想的。

EDIT2: 更好的方法:

var gainStrings = await Task.WhenAll(tasks1); 
+2

而不是'Select',你可以使用'WhenAll'的返回值,它将是每个任务所有结果的'string []'。 – Servy 2013-05-02 14:30:43

+0

根据这个:http://msdn.microsoft.com/en-us/library/hh194874.aspx只有当你给它一个数组时,它才会这样做。 – 2013-05-02 14:33:15

+3

您不需要'ToArray()','Task.WhenAll()'也适用于'IEnumerable >'。 – svick 2013-05-02 14:35:06

相关问题