2013-05-02 11 views
14

Dzisiaj zastanawiałem się, jak przekształcić listę zadań, oczekując na każdy z nich. Rozważmy następujący przykład:Przekształcanie IEnumerable <Task<T>> asynchronicznie przez oczekiwanie na każde zadanie

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

Chciałbym przekształcić moje listy zadań bez foreach jednak ani anonimowa funkcja składni ani składni funkcji zwykle pozwala mi robić to, co robi mój foreach.

Czy muszę polegać na mojej foreach i List<T>, czy jest jakiś sposób, aby to zadziałało z IEnumerable<T> i wszystkimi jego zaletami?

+0

Dlaczego nie drugi skompilować? Co to jest komunikat o błędzie? Czy skompiluje się, jeśli dodasz brakujące 'ToList()' po 'Wybierz'? –

+1

to dlatego, że zwraca 'IEnumerable >'. – GameScripting

Odpowiedz

23

Co o tym:

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

Poczekaj na wszystkich zadań do końca, a następnie wyodrębnić wyników. Jest to idealne rozwiązanie, jeśli nie zależy Ci na tym, w jakiej kolejności zostały zakończone.

EDIT2: Nawet lepszy sposób:

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

Zamiast "Wybierz" można po prostu użyć zwracanej wartości "Kiedykolwiek", będzie to "ciąg []" wszystkich wyników każdego zadania. – Servy

+0

Zgodnie z tym: http://msdn.microsoft.com/en-us/library/hh194874.aspx zrobi to tylko, jeśli dasz mu tablicę. –

+3

Nie potrzebujesz 'ToArray()', 'Task.WhenAll()' działa również dla 'IEnumerable >'. – svick

Powiązane problemy