2009-10-02 13 views
128

Eventuali duplicati:
Linq equivalent of foreach for IEnumerableLinq stile "per ogni"

C'è qualche sintassi LINQ stile per "Per ogni" operazioni?

Per esempio, aggiungere i valori sulla base di una collezione all'altra, già esistente:

IEnumerable<int> someValues = new List<int>() { 1, 2, 3 }; 

IList<int> list = new List<int>(); 

someValues.ForEach(x => list.Add(x + 1)); 

Invece di

foreach(int value in someValues) 
{ 
    list.Add(value + 1); 
} 
+0

correlati a questa domanda, ma non del tutto una vittima: http://stackoverflow.com/questions/858978/lambda-expression-using-foreach-clause – LukeH

+3

Vedi anche questo post del blog di Eric Lippert, per quanto riguarda la motivazione per non includere 'ForEach' nel BCL: http://blogs.msdn.com/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx – LukeH

+0

http://stackoverflow.com/questions/200574/linq-equivalent-of-foreach-per-ienumerable – aku

risposta

187

Utilizzando la ToList() metodo di estensione è la scelta migliore:

Non esiste un metodo di estensione nel BCL che implementa ForEach direttamente.


Anche se non c'è nessun metodo di estensione nel BCL che fa questo, non v'è ancora un'opzione nel System namespace ... se si aggiunge Reactive Extensions al progetto:

using System.Reactive.Linq; 

someValues.ToObservable().Subscribe(x => list.Add(x + 1)); 

Questo ha lo stesso risultato finale dell'uso sopra di ToList, ma è (in teoria) più efficiente, perché trasmette i valori direttamente al delegato.

+4

Ricorda che questo non è l'ideale per un elenco molto lungo, poiché esegue una copia dell'intero elenco prima di eseguirne il ciclo. –

+6

La chiamata di 'ToList' seguita da' ForEach' implica l'iterazione attraverso la raccolta originale due volte. Preferirei un ciclo standard 'foreach' ogni giorno: meno tipizzazione, più leggibile e prestazioni migliori:' foreach (var x in alcuniValori) list.Add (x + 1); ' – LukeH

+20

Per chi vede questo e pensa che sia un buona risposta, non è così. È pazzesco inefficiente. Vedi la risposta di Noldorin per il modo corretto di fare le cose. – Steve

2

Non c'è nulla di simile in Linq standard, ma c'è un operatore ForEach in MoreLinq.

67

Le classi Array e List<T> dispongono già di metodi ForEach, ma solo questa specifica implementazione. (Si noti che il primo è static, a proposito).

Non è sicuro che offra un grande vantaggio rispetto a un'istruzione foreach, ma è possibile scrivere un metodo di estensione per eseguire il lavoro per tutti gli oggetti IEnumerable<T>.

Ciò consentirebbe al codice esatto che hai postato nella tua domanda di funzionare esattamente come desideri.

+0

Grazie, è chiaro che potrei scrivere l'estensione me stesso. Voglio solo usare cose integrate il più possibile prima di fare questo. –

+0

Sì, è abbastanza giusto. Mi assicuro inoltre di non reinventare la funzionalità BCL. In questo caso, non ce ne sono tuttavia. – Noldorin

+0

La classe array non ha un metodo ForEach :) ma esiste una classe statşc "EnumerableExtensions" nello spazio dei nomi Microsoft.Practices.ObjectBuilder2. ha foreach metodo per IEnumerable :) – ArgeKumandan

22

non c'è nulla di built-in, ma si può facilmente creare il proprio metodo di estensione per farlo:

public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) 
{ 
    if (source == null) throw new ArgumentNullException("source"); 
    if (action == null) throw new ArgumentNullException("action"); 

    foreach (T item in source) 
    { 
     action(item); 
    } 
} 
12

La linea ufficiale MS è "perché non è un'operazione funzionale" (cioè si tratta di un operazione stateful).

Non potrebbe fare qualcosa di simile:

list.Select(x => x+1) 

o se si ha realmente bisogno in un elenco:

var someValues = new List<int>(list.Select(x => x+1)); 
+2

Hai un punto sulle operazioni funzionali vs. stateful. Tuttavia, F # è stato progettato come una lunghezza funzionale e ha un metodo 'ForEach' equivalente. – Noldorin

1

Non v'è alcuna estensione LINQ foreach.Tuttavia, la classe List ha un metodo ForEach su di esso, se sei disposto a utilizzare direttamente lo List.

Per quello che vale, il foreach sintassi standard vi darà i risultati desiderati ed è probabilmente più facile da leggere:

foreach (var x in someValues) 
{ 
    list.Add(x + 1); 
} 

Se sei irremovibile si desidera un'estensione stile LINQ. è banale implementarlo da solo.

public static void ForEach<T>(this IEnumerable<T> @this, Action<T> action) 
{ 
    foreach (var x in @this) 
     action(x); 
} 
Problemi correlati