Equivalente LINQ di foreach per IEnumerable <T>


716

Mi piacerebbe fare l'equivalente di quanto segue in LINQ, ma non riesco a capire come:

IEnumerable<Item> items = GetItems();
items.ForEach(i => i.DoStuff());

Qual è la vera sintassi?


99
Considera "foreach" vs. "ForEach" di Eric Lippert. Fornisce una buona giustificazione per non utilizzare / fornire a ForEach().

4
@pst: ero solito attaccare ciecamente questi metodi di estensione nei miei progetti. Grazie per quell'articolo.
Robin Maben,


2
Anche se non molto sexy, questo si adatta su una riga senza crearne una copia tramite ToList -foreach (var i in items) i.Dostuff();
James Westgate,

1
Alcuni di questi collegamenti sono morti! Qual è stato l'articolo così votato!
Warren

Risposte:


863

Non esiste alcuna estensione ForEach per IEnumerable; solo per List<T>. Quindi potresti farlo

items.ToList().ForEach(i => i.DoStuff());

In alternativa, scrivi il tuo metodo di estensione ForEach:

public static void ForEach<T>(this IEnumerable<T> enumeration, Action<T> action)
{
    foreach(T item in enumeration)
    {
        action(item);
    }
}

213
Fai attenzione a ToList (), perché ToList () crea una copia della sequenza, che potrebbe causare problemi di prestazioni e memoria.
decasteljau,

15
Ci sono alcuni motivi per cui ".Foreach ()" sarà migliore. 1. Multithreading, possibile tramite PLINQ. 2. Eccezioni, potresti voler raccogliere tutte le eccezioni nel loop e lanciarle immediatamente; e sono codici di rumore.
Dennis C,

12
PLINQ usa ForAll not ForEach, motivo per cui non dovresti usare ForEach.
user7116,

9
È necessario restituire un IENumerable<T>metodo di estensione. Mi piace:public static IEnumerable<T> ForAll<T>(this IEnumerable<T> numeration, Action<T> action) { foreach (T item in enumeration) { action(item); } return enumeration; }
Kees C. Bakker,

22
Si noti che nel primo caso lo sviluppatore 1) non risparmia quasi nessuna digitazione e 2) alloca inutilmente la memoria per memorizzare l'intera sequenza come elenco prima di buttarla via. Pensa prima di te LINQ
Mark Sowul il

364

Fredrik ha fornito la correzione, ma potrebbe valere la pena considerare perché questo non è nel framework per cominciare. Credo che l'idea sia che gli operatori di query LINQ dovrebbero essere privi di effetti collaterali, adattandosi a un modo ragionevolmente funzionale di guardare il mondo. Chiaramente ForEach è esattamente l'opposto: un costrutto basato esclusivamente sugli effetti collaterali.

Questo non vuol dire che questa è una brutta cosa da fare - solo pensare alle ragioni filosofiche dietro la decisione.


44
Eppure, F # ha Seq.iter
Stephen Swensen il

6
Tuttavia, c'è una cosa molto utile che le funzioni LINQ forniscono in genere che foreach () non lo fa - la funzione anonima assunta dalle funzioni Linq può anche prendere un indice come parametro, mentre con foreach è necessario ricostruire il classico per (int i .. ) costrutto. E i linguaggi funzionali devono consentire l'iterazione che ha effetti collaterali - altrimenti non potresti mai fare un giro di lavoro con loro :) Vorrei sottolineare che il metodo funzionale tipico sarebbe quello di restituire l'enumerabile originale invariato.
Walt W,

3
@Walt: Non sono ancora sicuro di essere d'accordo, in parte perché un tipico approccio veramente funzionale non userebbe foreach in questo modo ... userebbe un approccio funzionale più simile a LINQ, creando una nuova sequenza.
Jon Skeet,

12
@Stephen Swensen: sì, F # ha Seq.iter, ma F # ha anche strutture di dati immutabili. quando si utilizza Seq.iter su questi, il Seq originale non viene modificato; viene restituito un nuovo Seq con gli elementi con effetto laterale.
Anders,

7
@Anders - Seq.iternon restituisce nulla, figuriamoci un nuovo seq con elementi a effetto laterale. Si tratta solo di effetti collaterali. Potresti pensare Seq.map, perché Seq.iterè esattamente equivalente a un ForEachmetodo di estensione su IEnumerabe<_>.
Joel Mueller

39

Aggiornamento del 17/07/2012: apparentemente a partire da C # 5.0, il comportamento foreachdescritto di seguito è stato modificato e " l'uso di una foreachvariabile di iterazione in un'espressione lambda nidificata non produce più risultati imprevisti. " Questa risposta non si applica a C # ≥ 5.0 .

@ John Skeet e tutti coloro che preferiscono la parola chiave foreach.

Il problema con "foreach" in C # prima della 5.0 è che non è coerente con il modo in cui l'equivalente "per comprensione" funziona in altre lingue e con come mi aspetto che funzioni (opinione personale dichiarata qui solo perché altri hanno menzionato il loro opinione sulla leggibilità). Consulta tutte le domande relative a " Accesso alla chiusura modificata " e " Chiusura sulla variabile loop considerata dannosa ". Questo è solo "dannoso" a causa del modo in cui "foreach" è implementato in C #.

Prendi i seguenti esempi usando il metodo di estensione funzionalmente equivalente a quello nella risposta di @Fredrik Kalseth.

public static class Enumerables
{
    public static void ForEach<T>(this IEnumerable<T> @this, Action<T> action)
    {
        foreach (T item in @this)
        {
            action(item);
        }
    }
}

Ci scusiamo per l'esempio eccessivamente inventato. Sto solo usando Observable perché non è del tutto inverosimile fare qualcosa del genere. Ovviamente ci sono modi migliori per creare questo osservabile, sto solo cercando di dimostrare un punto. In genere il codice sottoscritto all'osservabile viene eseguito in modo asincrono e potenzialmente in un altro thread. Se si utilizza "foreach", questo potrebbe produrre risultati molto strani e potenzialmente non deterministici.

Il seguente test che utilizza il metodo di estensione "ForEach" supera:

[Test]
public void ForEachExtensionWin()
{
    //Yes, I know there is an Observable.Range.
    var values = Enumerable.Range(0, 10);

    var observable = Observable.Create<Func<int>>(source =>
                            {
                                values.ForEach(value => 
                                    source.OnNext(() => value));

                                source.OnCompleted();
                                return () => { };
                            });

    //Simulate subscribing and evaluating Funcs
    var evaluatedObservable = observable.ToEnumerable().Select(func => func()).ToList();

    //Win
    Assert.That(evaluatedObservable, 
        Is.EquivalentTo(values.ToList()));
}

Quanto segue non riesce con l'errore:

Previsto: equivalente a <0, 1, 2, 3, 4, 5, 6, 7, 8, 9> Ma era: <9, 9, 9, 9, 9, 9, 9, 9, 9, 9>

[Test]
public void ForEachKeywordFail()
{
    //Yes, I know there is an Observable.Range.
    var values = Enumerable.Range(0, 10);

    var observable = Observable.Create<Func<int>>(source =>
                            {
                                foreach (var value in values)
                                {
                                    //If you have resharper, notice the warning
                                    source.OnNext(() => value);
                                }
                                source.OnCompleted();
                                return () => { };
                            });

    //Simulate subscribing and evaluating Funcs
    var evaluatedObservable = observable.ToEnumerable().Select(func => func()).ToList();

    //Fail
    Assert.That(evaluatedObservable, 
        Is.EquivalentTo(values.ToList()));
}

Cosa dice l'avviso resharper?
reggaeguitar,

1
@reggaeguitar Non uso C # da 7 o 8 anni, da quando è stato rilasciato C # 5.0, che ha cambiato il comportamento descritto qui. Al momento ha emesso questo avviso stackoverflow.com/questions/1688465/… . Dubito comunque che lo avverta ancora.
drstevens,

34

È possibile utilizzare l' FirstOrDefault()estensione, che è disponibile per IEnumerable<T>. Tornando falsedal predicato, verrà eseguito per ogni elemento ma non gli importerà che non trovi effettivamente una corrispondenza. Questo eviterà il ToList()sovraccarico.

IEnumerable<Item> items = GetItems();
items.FirstOrDefault(i => { i.DoStuff(); return false; });

11
Anch'io sono d'accordo. Potrebbe essere un piccolo trucco intelligente, ma a prima vista, questo codice non è chiaro cosa stia facendo, sicuramente in confronto a un ciclo foreach standard.
Connell,

26
Ho dovuto sottovalutare perché, sebbene tecnicamente corretto, il tuo sé futuro e tutti i tuoi successori ti odieranno per sempre perché invece di foreach(Item i in GetItems()) { i.DoStuff();}te ha preso più personaggi e lo ha reso estremamente confuso
Mark Sowul,

14
Ok, ma soprattutto un trucco più leggibile:items.All(i => { i.DoStuff(); return true; }
nawfal,

5
So che questo è un post piuttosto vecchio, ma ho dovuto ridimensionarlo anche. Sono d'accordo che è un trucco intelligente, ma non è mantenibile. A prima vista sembra che stia facendo qualcosa solo con il primo elemento nell'elenco. Ciò potrebbe facilmente causare più bug in futuro da programmatori che fraintendono il modo in cui funziona e cosa dovrebbe fare.
Lee,

4
Questa è la programmazione degli effetti collaterali e l'IMHO scoraggiato.
Anish,

21

Ho preso il metodo di Fredrik e modificato il tipo di ritorno.

In questo modo, il metodo supporta l' esecuzione differita come altri metodi LINQ.

EDIT: se ciò non fosse chiaro, qualsiasi utilizzo di questo metodo deve terminare con ToList () o in qualsiasi altro modo per forzare il metodo a funzionare sull'enumerabile completo. Altrimenti, l'azione non verrebbe eseguita!

public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enumeration, Action<T> action)
{
    foreach (T item in enumeration)
    {
        action(item);
        yield return item;
    }
}

Ed ecco il test per aiutarti a vederlo:

[Test]
public void TestDefferedExecutionOfIEnumerableForEach()
{
    IEnumerable<char> enumerable = new[] {'a', 'b', 'c'};

    var sb = new StringBuilder();

    enumerable
        .ForEach(c => sb.Append("1"))
        .ForEach(c => sb.Append("2"))
        .ToList();

    Assert.That(sb.ToString(), Is.EqualTo("121212"));
}

Se rimuovi ToList () alla fine, vedrai che il test fallisce poiché StringBuilder contiene una stringa vuota. Questo perché nessun metodo ha forzato l'enumerazione di ForEach.


L'implementazione alternativa di ForEachè interessante, tuttavia non corrisponde al comportamento di List.ForEach, la cui firma è public void ForEach(Action<T> action). Inoltre, non corrisponde al comportamento Observable.ForEachdell'estensione IObservable<T>, la cui firma è public static void ForEach<TSource>(this IObservable<TSource> source, Action<TSource> onNext). FWIW, l' ForEachequivalente nelle collezioni Scala, anche quelle che sono pigre, hanno anche un tipo di ritorno che è equivalente a vuoto in C #.
drstevens,

Questa è la risposta migliore: esecuzione differita + API fluente.
Alexander Danilov,

3
Questo funziona esattamente come chiamare Selectcon ToList. Lo scopo ForEachè di non dover chiamare ToList. Dovrebbe essere eseguito immediatamente.
t3chb0t,

3
Quale sarebbe il vantaggio di avere questo "ForEach", la cui esecuzione è differita, rispetto a quella che viene eseguita immediatamente? Il differimento (che è scomodo nel modo in cui verrà utilizzato ForEach) non migliora il fatto che ForEach svolge un lavoro utile solo se l'azione ha effetti collaterali [la solita lamentela che viene fatta contro un tale operatore Linq]. Quindi, come fa questo cambiamento di aiuto? Inoltre, l'aggiunta di "ToList ()" per forzare l'esecuzione, non ha alcuno scopo utile. È un incidente in attesa di accadere. Il punto di "ForEach" sono i suoi effetti collaterali. Se VUOI un elenco restituito, SELEZIONA ha più senso.
ToolmakerSteve

20

Tieni i tuoi effetti collaterali fuori dal mio IEnumerable

Mi piacerebbe fare l'equivalente di quanto segue in LINQ, ma non riesco a capire come:

Come altri hanno sottolineato qui e all'estero LINQ eIEnumerable metodi dovrebbero essere privi di effetti collaterali.

Vuoi davvero "fare qualcosa" per ogni elemento in IEnumerable? Quindi foreachè la scelta migliore. Le persone non sono sorprese quando si verificano effetti collaterali qui.

foreach (var i in items) i.DoStuff();

Scommetto che non vuoi un effetto collaterale

Tuttavia, nella mia esperienza, gli effetti collaterali di solito non sono richiesti. Il più delle volte c'è una semplice query LINQ in attesa di essere scoperta accompagnata da una risposta StackOverflow.com di Jon Skeet, Eric Lippert o Marc Gravell che spiega come fare quello che vuoi!

Qualche esempio

Se in realtà stai solo aggregando (accumulando) del valore, dovresti considerare il Aggregatemetodo di estensione.

items.Aggregate(initial, (acc, x) => ComputeAccumulatedValue(acc, x));

Forse vuoi creare un nuovo IEnumerabledai valori esistenti.

items.Select(x => Transform(x));

O forse vuoi creare una tabella di ricerca:

items.ToLookup(x, x => GetTheKey(x))

L'elenco (gioco di parole non interamente inteso) delle possibilità potrebbe continuare all'infinito.


7
Ah, quindi Seleziona è Mappa e Aggregato è Riduci.
Darrel Lee,

17

Se si desidera agire come i rotoli di enumerazione, è necessario cedere ciascun articolo.

public static class EnumerableExtensions
{
    public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enumeration, Action<T> action)
    {
        foreach (var item in enumeration)
        {
            action(item);
            yield return item;
        }
    }
}

Questo non è davvero un forEach quando si restituisce l'articolo, è più simile a un tocco.
EluciusFTW

10

Esiste una versione sperimentale di Microsoft di Interactive Extensions per LINQ (anche su NuGet , vedere il profilo di RxTeams per ulteriori collegamenti). Il video di Channel 9 lo spiega bene.

I suoi documenti sono forniti solo in formato XML. Ho eseguito questa documentazione in Sandcastle per consentirmi di essere in un formato più leggibile. Decomprimi l'archivio documenti e cerca index.html .

Tra le tante altre chicche, fornisce l'implementazione di ForEach prevista. Ti permette di scrivere codice in questo modo:

int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8 };

numbers.ForEach(x => Console.WriteLine(x*x));

2
Il link funzionante alle estensioni interattive: microsoft.com/download/en/details.aspx?id=27203
Maciek Świszczowski

8

Secondo PLINQ (disponibile da .Net 4.0), puoi fare un

IEnumerable<T>.AsParallel().ForAll() 

per eseguire un ciclo foreach parallelo su un IEnumerable.


fintanto che la tua azione è sicura, tutto va bene. ma cosa succederà se devi eseguire un'azione non thread-safe? può causare un bel caos ...
shirbr510,

2
Vero. Non è thread-safe, verranno utilizzati thread diversi da alcuni pool di thread ... E ho bisogno di rivedere la mia risposta. Non c'è ForEach () quando lo provo ora .. Deve essere stato il mio codice contenente un'estensione con ForEach quando ho riflettuto su questo.
Wolf5,

6

Lo scopo di ForEach è quello di causare effetti collaterali. IEnumerable è per l'enumerazione lazy di un set.

Questa differenza concettuale è abbastanza visibile se la consideri.

SomeEnumerable.ForEach(item=>DataStore.Synchronize(item));

Questo non verrà eseguito fino a quando non si esegue un "count" o un "ToList ()" o qualcosa del genere. Chiaramente non è ciò che si esprime.

È necessario utilizzare le estensioni di IEnumerable per impostare catene di iterazioni, definendo il contenuto in base alle rispettive fonti e condizioni. Gli alberi delle espressioni sono potenti ed efficienti, ma dovresti imparare ad apprezzare la loro natura. E non solo per programmare intorno a loro per salvare alcuni personaggi che prevalgono sulla valutazione pigra.


5

Molte persone lo hanno menzionato, ma ho dovuto scriverlo. Non è questo il più chiaro / più leggibile?

IEnumerable<Item> items = GetItems();
foreach (var item in items) item.DoStuff();

Breve e semplice (st).


Puoi eliminare l'intera prima riga e utilizzare GetItems direttamente in foreach
tymtam

3
Ovviamente. È scritto così per chiarezza. In modo che sia chiaro quale GetItems()metodo restituisce.
Nenad,

4
Ora, quando leggo il mio commento, vedo che ti sto dicendo qualcosa che non conosci. Non intendevo quello. Quello che volevo dire è che foreach (var item in GetItems()) item.DoStuff();è solo una bellezza.
Tymtam,

4

Ora abbiamo la possibilità di ...

        ParallelOptions parallelOptions = new ParallelOptions();
        parallelOptions.MaxDegreeOfParallelism = 4;
#if DEBUG
        parallelOptions.MaxDegreeOfParallelism = 1;
#endif
        Parallel.ForEach(bookIdList, parallelOptions, bookID => UpdateStockCount(bookID));

Naturalmente, questo apre una nuova lattina di filari.

ps (mi dispiace per i caratteri, è quello che il sistema ha deciso)


4

Come già indicato da numerose risposte, puoi facilmente aggiungere un tale metodo di estensione da solo. Tuttavia, se non vuoi farlo, anche se non sono a conoscenza di nulla di simile nel BCL, c'è ancora un'opzione nello Systemspazio dei nomi, se hai già un riferimento all'estensione reattiva (e se non lo fai , avresti dovuto):

using System.Reactive.Linq;

items.ToObservable().Subscribe(i => i.DoStuff());

Sebbene i nomi dei metodi siano leggermente diversi, il risultato finale è esattamente quello che stai cercando.


Sembra che quel pacchetto sia ormai obsoleto
reggaeguitar il

3

Ognuno può anche essere incatenato , appena rimesso in linea dopo l'azione. rimanere fluente


Employees.ForEach(e=>e.Act_A)
         .ForEach(e=>e.Act_B)
         .ForEach(e=>e.Act_C);

Orders  //just for demo
    .ForEach(o=> o.EmailBuyer() )
    .ForEach(o=> o.ProcessBilling() )
    .ForEach(o=> o.ProcessShipping());


//conditional
Employees
    .ForEach(e=> {  if(e.Salary<1000) e.Raise(0.10);})
    .ForEach(e=> {  if(e.Age   >70  ) e.Retire();});

Una versione desiderosa di implementazione.

public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enu, Action<T> action)
{
    foreach (T item in enu) action(item);
    return enu; // make action Chainable/Fluent
}

Modifica: una versione Lazy utilizza il rendimento, in questo modo .

public static IEnumerable<T> ForEachLazy<T>(this IEnumerable<T> enu, Action<T> action)
{
    foreach (var item in enu)
    {
        action(item);
        yield return item;
    }
}

La versione Lazy DEVE essere materializzata, ad esempio ToList (), altrimenti non succede nulla. vedi sotto grandi commenti da ToolmakerSteve.

IQueryable<Product> query = Products.Where(...);
query.ForEachLazy(t => t.Price = t.Price + 1.00)
    .ToList(); //without this line, below SubmitChanges() does nothing.
SubmitChanges();

Tengo ForEach () e ForEachLazy () nella mia libreria.


2
Hai provato questo? Esistono diversi contesti in cui questo metodo si comporta in modo intuitivo. Meglio sarebbeforeach(T item in enu) {action(item); yield return item;}
Taemyr,

2
Ciò comporterà più enumerazioni
regisbsb

Interessante. Riflettendo su quando vorrei fare quanto sopra, per una sequenza di 3 azioni, anziché foreach (T item in enu) { action1(item); action2(item); action3(item); }? Un singolo ciclo esplicito. Immagino che fosse importante fare tutte le azioni1 PRIMA di iniziare a fare le azioni2.
ToolmakerSteve

@ Rm558 - il tuo approccio utilizza "return return". Pro: enumera la sequenza originale solo una volta, quindi funziona correttamente con una più ampia gamma di enumerazioni. Contro: se alla fine si dimentica ".ToArray ()", non succede nulla. Anche se il fallimento sarà evidente, non trascurato a lungo, quindi non un costo maggiore. Non "mi sento pulito" per me, ma è il giusto compromesso, se si sta seguendo questa strada (un operatore ForEach).
ToolmakerSteve

1
Questo codice non è sicuro dal punto di vista transazionale. E se fallisse ProcessShipping()? Hai un acquirente e-mail, addebitato la sua carta di credito, ma non gli hai mai inviato le sue cose? Sicuramente chiedendo problemi.
zmechanic,

2

Questa astrazione "approccio funzionale" perde molto tempo. Niente a livello linguistico impedisce effetti collaterali. Finché puoi farlo chiamare lambda / delegato per ogni elemento nel contenitore, otterrai il comportamento "ForEach".

Ecco ad esempio un modo per unire srcDictionary in destDictionary (se la chiave esiste già - sovrascrive)

questo è un trucco e non dovrebbe essere usato in nessun codice di produzione.

var b = srcDictionary.Select(
                             x=>
                                {
                                  destDictionary[x.Key] = x.Value;
                                  return true;
                                }
                             ).Count();

6
Se devi aggiungere quel disclaimer, probabilmente non dovresti pubblicarlo. Solo la mia opinione.
Andrew Grothe,

2
Come diavolo è meglio di foreach(var tuple in srcDictionary) { destDictionary[tuple.Key] = tuple.Value; }? Se non nel codice di produzione dove e perché dovresti mai usarlo?
Mark Sowul il

3
Questo solo per dimostrarlo è possibile in linea di principio. Capita anche di fare ciò che OP ha richiesto, e ho chiaramente indicato che non dovrebbe essere usato in produzione, ancora curioso e ha valore educativo.
Zar Shardan,

2

Ispirato da Jon Skeet, ho esteso la sua soluzione con quanto segue:

Metodo di estensione:

public static void Execute<TSource, TKey>(this IEnumerable<TSource> source, Action<TKey> applyBehavior, Func<TSource, TKey> keySelector)
{
    foreach (var item in source)
    {
        var target = keySelector(item);
        applyBehavior(target);
    }
}

Cliente:

var jobs = new List<Job>() 
    { 
        new Job { Id = "XAML Developer" }, 
        new Job { Id = "Assassin" }, 
        new Job { Id = "Narco Trafficker" }
    };

jobs.Execute(ApplyFilter, j => j.Id);

. . .

    public void ApplyFilter(string filterId)
    {
        Debug.WriteLine(filterId);
    }


1

Rispettosamente non sono d'accordo con l'idea che i metodi di estensione dei link dovrebbero essere liberi da effetti collaterali (non solo perché non lo sono, qualsiasi delegato può eseguire effetti collaterali).

Considera quanto segue:

   public class Element {}

   public Enum ProcessType
   {
      This = 0, That = 1, SomethingElse = 2
   }

   public class Class1
   {
      private Dictionary<ProcessType, Action<Element>> actions = 
         new Dictionary<ProcessType,Action<Element>>();

      public Class1()
      {
         actions.Add( ProcessType.This, DoThis );
         actions.Add( ProcessType.That, DoThat );
         actions.Add( ProcessType.SomethingElse, DoSomethingElse );
      }

      // Element actions:

      // This example defines 3 distict actions
      // that can be applied to individual elements,
      // But for the sake of the argument, make
      // no assumption about how many distict
      // actions there may, and that there could
      // possibly be many more.

      public void DoThis( Element element )
      {
         // Do something to element
      }

      public void DoThat( Element element )
      {
         // Do something to element
      }

      public void DoSomethingElse( Element element )
      {
         // Do something to element
      }

      public void Apply( ProcessType processType, IEnumerable<Element> elements )
      {
         Action<Element> action = null;
         if( ! actions.TryGetValue( processType, out action ) )
            throw new ArgumentException("processType");
         foreach( element in elements ) 
            action(element);
      }
   }

Quello che mostra l'esempio è in realtà solo una specie di associazione tardiva che consente di invocare una delle tante azioni possibili che hanno effetti collaterali su una sequenza di elementi, senza dover scrivere un costrutto switch grande per decodificare il valore che definisce l'azione e tradurre nel suo metodo corrispondente.


9
C'è una differenza tra se un metodo di estensione PU have avere effetti collaterali e se DOVREBBE avere. Stai solo sottolineando che può avere, mentre potrebbero esserci ottime ragioni per proporre che non dovrebbero avere effetti collaterali. Nella programmazione funzionale, tutte le funzioni sono prive di effetti collaterali e quando si utilizzano costrutti di programmazione funzionale è possibile supporre che lo siano.
Dave Van den Eynde,

1

Per rimanere fluenti si può usare un simile trucco:

GetItems()
    .Select(i => new Action(i.DoStuf)))
    .Aggregate((a, b) => a + b)
    .Invoke();


-1

Ancora un altro ForEachesempio

public static IList<AddressEntry> MapToDomain(IList<AddressModel> addresses)
{
    var workingAddresses = new List<AddressEntry>();

    addresses.Select(a => a).ToList().ForEach(a => workingAddresses.Add(AddressModelMapper.MapToDomain(a)));

    return workingAddresses;
}

4
Che spreco di memoria. Questo chiama ToList per aggiungere a un elenco. Perché questo non restituisce solo gli indirizzi.Seleziona (a => MapToDomain (a))?
Mark Sowul,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.