2013-05-02 11 views
14

Oggi mi chiedevo come trasformare un elenco di attività attendendo ciascuna di esse. consideri il seguente esempio:Trasforma IEnumerable <Task<T>> in modo asincrono in attesa di ogni attività

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

Mi piacerebbe trasformare la mia lista di compiti senza foreach, tuttavia sia la sintassi di funzione anonima, né la solita sintassi della funzione mi permette di fare quello che il mio foreach fa.

Devo fare affidamento sul mio foreach e sul List<T> o c'è un modo per farlo funzionare con IEnumerable<T> e tutti i suoi vantaggi?

+0

Perché il secondo non compilare? Qual è il messaggio di errore? Si compila se aggiungi il 'ToList()' mancante dopo il 'Select'? –

+1

perché restituisce 'IEnumerable >'. – GameScripting

risposta

23

Che dire di questo:

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

Attendere per tutte le attività alla fine e poi estrarre risultati. Questo è l'ideale se non ti interessa in quale ordine sono finiti.

EDIT2: modo ancora migliore:

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

Invece di 'Select' puoi semplicemente usare il valore di ritorno di' WhenAll', sarà una 'stringa []' di tutti i risultati di ciascuna attività. – Servy

+0

In base a ciò: http://msdn.microsoft.com/en-us/library/hh194874.aspx lo farà solo se gli dai un array. –

+3

Non è necessario il 'ToArray()', 'Task.WhenAll()' funziona per 'IEnumerable >'. – svick

Problemi correlati