2013-05-02 20 views
14

Hôm nay tôi đã tự hỏi làm thế nào để chuyển đổi một danh sách các nhiệm vụ bằng cách chờ đợi mỗi của nó. Hãy xem xét ví dụ sau:Chuyển đổi IEnumerable <Task<T>> không đồng bộ bằng cách chờ mỗi công việc

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; 
    } 
} 

Tôi muốn chuyển đổi danh sách các tác vụ mà không có sự foreach, tuy nhiên một trong hai cú pháp chức năng ẩn danh cũng không phải là chức năng cú pháp thông thường cho phép tôi làm những gì foreach của tôi không.

Tôi có phải dựa vào foreach của tôi và List<T> hoặc có cách nào để làm cho nó hoạt động với IEnumerable<T> và tất cả các ưu điểm của nó?

+0

Tại sao một giây không biên dịch? Thông báo lỗi là gì? Nó sẽ biên dịch nếu bạn thêm thiếu 'ToList()' sau 'Chọn'? –

+1

của nó vì nó trả về 'IEnumerable >'. – GameScripting

Trả lời

23

gì về điều này:

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

Chờ cho tất cả các nhiệm vụ nhằm chấm dứt và sau đó trích xuất kết quả. Điều này là lý tưởng nếu bạn không quan tâm đến thứ tự nào họ đã hoàn thành.

EDIT2: cách Thậm chí tốt hơn:

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

Thay vì 'Select' bạn chỉ có thể sử dụng giá trị trả về của' WhenAll', nó sẽ là một 'chuỗi []' của tất cả các kết quả của mỗi tác vụ. – Servy

+0

Theo điều này: http://msdn.microsoft.com/en-us/library/hh194874.aspx nó sẽ làm điều đó chỉ khi bạn cung cấp cho nó một mảng. –

+3

Bạn không cần 'ToArray()', 'Task.WhenAll()' làm việc cho 'IEnumerable >' quá. – svick

Các vấn đề liên quan