Vra

Ek wil graag om te doen, die ekwivalent van die volgende in LINQ, maar ek kan nie uitvind hoe:

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

Wat is die werklike sintaksis?

Was dit nuttig?

Oplossing

Daar is geen foreach uitbreiding vir IEnumerable; net vir List<T>. So jy kan doen

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

As alternatief, skryf jou eie foreach uitbreiding metode:

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

Ander wenke

Fredrik het op voorwaarde dat die fix, maar dit kan die moeite werd oorweging wees waarom dit nie in die raamwerk te begin met. Ek glo die idee is dat die LINQ navraag operateurs newe-effek-vry moet wees, pas in 'n redelik funksionele manier van kyk na die wêreld. Dit is duidelik dat foreach is presies die teenoorgestelde -. 'N suiwer newe-effek-gebaseerde konstruksie

Dit is nie te sê dit is 'n slegte ding om te doen -. Net te dink oor die filosofiese redes agter die besluit

Update 2012/07/17: Blykbaar as van C # 5,0, die gedrag van foreach hieronder beskryf is verander en " die gebruik van 'n foreach iterasie veranderlike in 'n sub-lambda uitdrukking produseer nie meer onverwagse resultate. " Dit antwoord nie van toepassing op C # ≥ 5.0.

@John Skeet en elkeen wat die foreach navraag verkies.

Die probleem met "foreach" in C # voor 5.0 , is dat dit strydig is met hoe die ekwivalent" vir begrip "werk in ander tale, en met hoe ek sou verwag dat dit werk (persoonlike mening gestel hier net omdat ander genoem het hul mening oor leesbaarheid). Sien al die vrae oor " Toegang tot wysiging sluiting " sowel as " Sluiting oor die lus veranderlike beskou skadelike ". Dit is net "skadelike" as gevolg van die manier waarop "foreach" geïmplementeer word in C #.

Neem die volgende voorbeelde gebruik te maak van die funksioneel ekwivalent uitbreiding metode om dit in antwoord @Fredrik Kalseth se.

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

Jammer vir die té slinks voorbeeld. Ek is net die gebruik van Waarneembare, want dit is nie heeltemal vergesog om so iets te doen. Dit is duidelik dat daar is beter maniere om hierdie waarneembaar skep, ek net 'n poging om 'n punt te demonstreer. Tipies die kode ingeskryf is by die waarneembare is asynchroon en potensieel uitgevoer in 'n ander draad. As die gebruik van "foreach", kan dit baie vreemd en potensieel nie-deterministiese resultate te lewer.

Die volgende toets met behulp van "foreach" uitbreiding metode gaan:

[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()));
}

Die volgende versuim deur die dwaling:

Verwag: gelykstaande aan <0, 1, 2, 3, 4, 5, 6, 7, 8, 9>    Maar was: <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()));
}

Jy kan die FirstOrDefault() uitbreiding, wat beskikbaar is vir IEnumerable<T> is gebruik. Deur terug te keer false van die gesegde, sal dit uitgevoer word vir elke element, maar sal nie omgee dat dit 'n wedstryd nie eintlik nie vind. Dit sal die ToList() oorhoofse vermy.

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

Ek het Fredrik se metode en verander die tipe terugkeer.

Op hierdie manier, die metode ondersteun uitgestel uitvoering soos ander LINQ metodes.

Edit: As dit was nie duidelik nie, enige gebruik van hierdie metode moet eindig met ToList () of enige ander manier om die metode te dwing om te werk aan die volledige enumerable. Anders sou die aksie nie uitgevoer word!

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

En hier is die toets om te help sien dit:

[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"));
}

As jy die ToList () in die einde verwyder, sal jy sien die toets misluk omdat die StringBuilder 'n leë string bevat. Dit is omdat daar geen metode die foreach om te noem gedwing.

Hou jou Newe-effekte uit my IEnumerable

  
    

Ek wil graag die ekwivalent van die volgende in LINQ doen, maar ek kan nie uitvind hoe:

  

Soos ander het daarop gewys hier en in die buiteland LINQ en IEnumerable metodes sal na verwagting newe-effek vry wees.

Wil jy regtig om "iets te doen" om elke item in die IEnumerable? Dan is foreach die beste keuse. Mense is nie verbaas toe newe-effekte hier gebeur.

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

Ek is seker jy wil nie 'n newe-effek

Maar in my ervaring newe-effekte is gewoonlik nie nodig nie. Meer dikwels as nie daar is 'n eenvoudige LINQ navraag wag om ontdek te word vergesel deur 'n StackOverflow.com antwoord deur óf Jon kleiduiven, Eric Lippert, of Marc Gravell verduidelik hoe om te doen wat jy wil!

Voorbeelde

As jy eintlik net saamgevoeg (opbou) 'n waarde dan moet jy die Aggregate uitbreiding metode oorweeg.

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

Miskien wil jy 'n nuwe IEnumerable van die bestaande waardes te skep.

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

Of miskien het jy wil om te kyk-up tafel te skep:

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

Die lys (woordspeling nie heeltemal bedoel) van moontlikhede gaan aan en aan.

As jy wil om op te tree as die opsomming rolle moet jy elke item te lewer.

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

Daar is 'n eksperimentele vrylating deur Microsoft van Interaktiewe Uitbreidings aan LINQ (ook op NuGet , sien RxTeams se profiel vir meer links). Die Channel 9 video verduidelik dit goed .

Die dokumente is slegs bedoel in XML-formaat. Ek het hierdie dokumentasie in Sandkasteel hardloop toe te laat om dit te wees in 'n meer leesbare formaat. Pak die dokumente argief en kyk vir index.html .

Een van die vele ander goodies, dit bied die verwagte foreach implementering. Dit laat jou toe om kode soos hierdie te skryf:

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

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

Volgens PLINQ (beskikbaar sedert Net 4.0), kan jy dit doen 'n

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

'n parallel foreach lus doen op 'n IEnumerable.

Die doel van foreach is om newe-effekte veroorsaak. IEnumerable is vir lui opsomming van 'n stel.

Dit konseptuele verskil is nogal sigbaar wanneer jy dit oorweeg.

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

Dit sal nie uit te voer totdat jy 'n "telling" of 'n "ToList ()" of iets daarop doen. Dit is duidelik nie wat uitgedruk word.

Jy moet die IEnumerable uitbreidings gebruik vir die opstel van kettings van iterasie, definining inhoud deur hulle onderskeie bronne en voorwaardes. Uitdrukking Bome is 'n kragtige en doeltreffende, maar jy moet leer om hul aard waardeer. En nie net vir ontwikkeling rondom hulle 'n paar karakters red oorheersende lui evaluering.

Baie mense genoem nie, maar ek moes dit neer te skryf. Is Hy nie miskien die meeste duidelik / mees leesbare?

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

Kort en eenvoudige (st).

As talle antwoorde reeds uitwys, kan jy maklik voeg soos 'n uitbreiding metode jouself. Maar, as jy nie wil hê om dit te doen, maar ek is nie bewus van so iets in die BCL, daar is nog 'n opsie in die System naamruimte, as jy reeds 'n verwysing na Reaktiewe Uitbreiding (en as jy dit nie doen nie, moet jy '):

using System.Reactive.Linq;

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

Hoewel die metode name is 'n bietjie anders, die eindresultaat is presies wat jy soek.

Nou het ons die opsie van ...

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

Natuurlik is dit maak 'n hele nuwe blikkie haarwurms.

PS (Jammer oor die fonts, dit is wat die stelsel besluit)

Hierdie "funksionele benadering" abstraksie lekkasies groot tyd.Niks op die vlak van die taal verhoed dat newe-effekte.So lank As wat jy kan maak dit noem jou lambda/afgevaardigde vir elke element in die houer - jy sal kry die "ForEach" gedrag.

Hier is byvoorbeeld een manier om van die samesmelting srcDictionary in destDictionary (as sleutel reeds bestaan - skryf)

dit is'n hack, en moet nie gebruik word in enige produksie-kode.

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

geïnspireer deur Jon kleiduiven, het ek sy oplossing met die volgende uitgebrei:

Uitbreiding Metode:

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

Kliënt:

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

foreach kan ook Vasgeketting , net terug na die pileline na die werking te stel. bly vlot


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

'n Gretig weergawe van implementering.

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
}

Edit: 'n Lazy weergawe gebruik opbrengs terugkeer, soos hierdie .

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

Die Lazy weergawe behoeftes te bewaarheid, ToList () byvoorbeeld, anders, gebeur daar niks. sien hieronder opmerkings van ToolmakerSteve.

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

Ek hou beide foreach () en ForEachLazy () in my biblioteek.

Ek respectually nie saamstem met die idee dat uitbreiding metodes skakel moet newe-effek gratis (nie net omdat hulle nie kan enige afgevaardigde newe-effekte uit te voer).

wees

Oorweeg die volgende:

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

Wat die voorbeeld toon is regtig net 'n soort van laat-bindende wat toelaat dat een roep een van baie moontlike aksies met newe-effekte op 'n reeks van elemente, sonder om 'n groot skakelaar konstruk skryf aan die waarde wat die definieer ontsyfer aksie en vertaal dit in die ooreenstemmende metode.

Vir VB.NET wat jy moet gebruik:

listVariable.ForEach(Sub(i) i.Property = "Value")

Om vlot kan 'n mens so 'n truuk gebruik bly:

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

MoreLinq het IEnumerable<T>.ForEach en 'n ton van ander nuttige uitbreidings. Dit is waarskynlik nie die moeite werd om die afhanklikheid net vir ForEach, maar daar is 'n baie nuttige dinge in daar.

https://www.nuget.org/packages/morelinq/

https://github.com/morelinq/MoreLINQ

Nog 'n ForEach Voorbeeld

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;
}
Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top