IEnumeruojamas vs sąrašas - ką naudoti? Kaip jie veikia?

Turiu abejonių, kaip veikia skaitikliai, ir LINQ. Apsvarstykite šiuos du paprastus pasirinkimus:

 List<Animal> sel = (from animal in Animals join race in Species on animal.SpeciesKey equals race.SpeciesKey select animal).Distinct().ToList(); 

arba

 IEnumerable<Animal> sel = (from animal in Animals join race in Species on animal.SpeciesKey equals race.SpeciesKey select animal).Distinct(); 

Pakeitiau savo šaltinių objektų pavadinimus, kad tai atrodytų labiau bendras pavyzdys. Pats prašymas nėra toks svarbus. Noriu paklausti:

 foreach (Animal animal in sel) {  } 
  • Pastebėjau, kad jei aš IEnumerable , kai derinu ir patikrinsiu, kuris šiuo atveju yra IEnumerable, jis turi kelis įdomius narius: vidinį, išorinį, internalKeySelector ir ExternalKeySelector, šie paskutiniai 2, atrodo, yra delegatai. „Vidinis“ narys neturi „Gyvūnų“ atvejų, o „Rūšių“ atvejų, kurie man buvo labai keista. „Išorinis“ elementas apima „Gyvūnų“ atvejus. Manau, kad du delegatai nustato, kas vyksta ir kas išeina iš jo?

  • Pastebėjau, kad jei naudosiu „Distinct“, „vidinis“ yra 6 elementai (tai neteisinga, nes tik 2 yra „Distinct“), tačiau „išorėje“ yra teisingos vertės. Vėlgi, tikriausiai tai lemia deleguoti metodai, tačiau tai yra šiek tiek daugiau, nei žinau apie IEskaitomą.

  • Svarbiausia, kas iš dviejų variantų yra geriausias rezultatas?

Blogio sąrašo konvertavimas per .ToList() ?

Arba galbūt tiesiogiai naudojate skaitiklį?

Jei galite, prašome šiek tiek paaiškinti arba atsisakyti kai kurių nuorodų, paaiškinančių šį „IEnumerable“ naudojimą.

511
02 сент. „Axonn“ yra nustatytas 02 sept. 2010-09-02 18:05 '10, 18:05, 2010-09-02 18:05
@ 9 atsakymai

IEnumerable aprašo elgesį, o „List“ yra šio elgesio įgyvendinimas. Naudodamiesi „ IEnumerable , kompiliatoriui suteikiate galimybę vėluoti darbą ilgiau, galbūt optimizuodami pakeliui. Jei naudojate „ToList“ (), priversite kompiliatorių nedelsiant patvirtinti rezultatus.

Kai aš „įterpsiu“ LINQ išraiškas, naudoju IEnumerable , nes tik apibrėždamas elgesį, suteikiu LINQ galimybę atidėti sąmatą ir, galbūt, optimizuoti programą. Prisiminkite, kaip LINQ nesukuria SQL duomenų bazės užklausai, kol nepateiksite jo sąrašo? Apsvarstykite tai:

 public IEnumerable<Animals> AllSpotted() { return from a in Zoo.Animals where a.coat.HasSpots == true select a; } public IEnumerable<Animals> Feline(IEnumerable<Animals> sample) { return from a in sample where a.race.Family == "Felidae" select a; } public IEnumerable<Animals> Canine(IEnumerable<Animals> sample) { return from a in sample where a.race.Family == "Canidae" select a; } 

Dabar turite metodą, kuris pasirenka šaltinio pavyzdį („AllSpotted“), taip pat kai kuriuos filtrus. Dabar galite tai padaryti:

 var Leopards = Feline(AllSpotted()); var Hyenas = Canine(AllSpotted()); 

Taigi ar greičiau naudoti „List over IEnumerable ? Tik jei norite neleisti, kad prašymas būtų įvykdytas daugiau nei vieną kartą. Bet ar apskritai tai geriau? Pirmiau pateiktame pavyzdyje leopardai ir henas paverčiami į vieną SQL užklausą, o duomenų bazė grąžina tik tas reikšmes turinčias eilutes. Bet jei grąžiname sąrašą iš „ AllSpotted() , jis gali veikti lėčiau, nes duomenų bazė gali grąžinti daug daugiau duomenų nei iš tikrųjų reikia, o klientui praleidžiame filtravimo kilpas.

Programoje gali būti geriau atidėti jūsų užklausos konversiją į sąrašą iki pat pabaigos, todėl, jei ketinu išvardyti daugiau nei vieną kartą per Leopardus ir Hyenas, atliksiu šiuos veiksmus:

 List<Animals> Leopards = Feline(AllSpotted()).ToList(); List<Animals> Hyenas = Canine(AllSpotted()).ToList(); 
576
02 сент. Atsakymą pateikė C. Lawrence Wenham 02 Sep. 2010-09-02 18:36 '10, 18:36, 2010-09-02 18:36

Klasė, diegianti IEnumerable leidžia naudoti foreach sintaksę.

Iš esmės jis turi galimybę gauti kitą kolekcijos elementą. Jis nereikalauja visos kolekcijos, kad būtų atmintyje ir nežino, kiek elementų jame, foreach tik toliau gauna kitą elementą, kol jis baigiasi.

Tai gali būti labai naudinga esant tam tikroms aplinkybėms, pavyzdžiui, masinėje duomenų bazės lentelėje, kurios nenorite kopijuoti viso atminties prieš pradedant apdorojimo eilutes.

Dabar List įgyvendina IEnumerable , bet atitinka visą atmintyje esančią kolekciją. Jei turite „ IEnumerable ir skambinate .ToList() , sukuriate naują sąrašą su atmintyje .ToList() “ turiniu.

Jūsų linq išraiška grąžina skaičiavimą, ir pagal nutylėjimą išraiška vykdoma pakartotinai su foreach . IEnumerable linq pareiškimas vykdomas, kai kartojate foreach , bet jūs galite priversti jį kartoti greičiau .ToList() .

Štai ką aš turiu galvoje:

 var things = from item in BigDatabaseCall() where .... select item; // this will iterate through the entire linq statement: int count = things.Count(); // this will stop after iterating the first one, but will execute the linq again bool hasAnyRecs = things.Any(); // this will execute the linq statement *again* foreach( var thing in things ) ... // this will copy the results to a list in memory var list = things.ToList() // this won't iterate through again, the list knows how many items are in it int count2 = list.Count(); // this won't execute the linq statement - we have it copied to the list foreach( var thing in list ) ... 
103
02 сент. Atsakymą pateikė Keith 02 Sep. 2010-09-02 18:24 '10, 18:24, 2010-09-02 18:24

Yra labai geras straipsnis parašytas: Claudio Bernasconi TechBlog čia: Kada naudoti IEnumerable, ICollection, IList ir List

Štai keletas svarbiausių scenarijų ir funkcijų:

2019

91
04 июня '15 в 17:07 2015-06-04 17:07 atsakymą pateikė rubStackOverflow birželio 15 d. 15 val. 17:07 2015-06-04 17:07

Svarbiausia yra suprasti, kad naudojant „Linq“ užklausa nedelsiant negalioja. Jis vyksta tik kaip iteracijos dalis, kurią sukelia IEnumerable<T> kuriuos daro visi keistieji delegatai.

Taigi, pirmasis pavyzdys nedelsdamas įvertina užklausą skambindamas „ ToList ir pateikdamas užklausos rezultatus sąraše.
Antrasis pavyzdys grąžina „ IEnumerable<T> , kuriame yra visa informacija, reikalinga užklausai atlikti vėliau.

Kalbant apie našumą, atsakymas priklauso. Jei jums reikia iš karto įvertinti rezultatus (tarkim, jūs esate mutavusios struktūros, kurias prašote vėliau, arba jei nenorite, kad iteracija per IEnumerable<T> užtruks ilgai), naudokite sąrašą. Priešingu atveju naudokite „ IEnumerable<T> . Pagal numatytuosius nustatymus antrajame pavyzdyje turėtų būti naudojamas užsakomosios vertės įvertinimas, nes paprastai naudojama mažiau atminties, nebent yra konkrečių priežasčių, dėl kurių rezultatai būtų saugomi sąraše.

63
02 сент. atsakymą pateikė „ Thecoop 02 Sep 2010-09-02 18:08 '10, 18:08, 2010-09-02 18:08

Niekas paminėjo vieną esminį skirtumą, ironiškai atsakė į klausimą, uždarytą kaip dubliuotas.

„IEnumerable“ yra tik skaitomas, tačiau „List“ nėra.

Žr. Praktinis skirtumas tarp sąrašo ir IE.

55
09 дек. Atsakymas suteiktas CAD gruodį 09 gruodis. 2014-12-09 11:30 '14, 11:30, 2014-12-09 11:30

IEnumerable privalumas yra atidėtas vykdymas (paprastai su duomenų bazėmis). Užklausa nebus vykdoma tol, kol neatsirasite duomenų. Tai prašymas, laukiantis, kol jis bus reikalingas (dar žinomas kaip tingus pakrovimas).

Jei skambinate „ToList“, prašymas bus įvykdytas arba „įvykdytas“, kaip norėčiau pasakyti.

Abiem yra privalumų ir trūkumų. Jei skambinate „ToList“, galite ištrinti kai kurias paslaptis apie tai, kada bus įvykdytas prašymas. Jei prilipsite prie „IEnumerable“, gausite pranašumą, kad programa neveikia tol, kol ji nebus reikalinga.

33
02 сент. atsakymas, kurį pateikė Matt Sherman 02 sep. 2010-09-02 18:13 '10, 18:13, 2010-09-02 18:13

Jei viskas, ką norite padaryti, yra sąrašas, naudokite IEnumerable .

Tačiau ToList kad ToList šaltinių rinkinio keitimas yra pavojinga operacija - šiuo atveju pirmiausia norite „ ToList . Taip kiekvienam atmintyje esančiam elementui bus sukurtas naujas sąrašo elementas, kuriame bus nurodytas „ IEnumerable ir todėl jis bus mažiau veiksmingas, jei tik vieną kartą užsirašysite, bet jis yra saugesnis, o kartais List metodai yra patogūs (pavyzdžiui, atsitiktine prieiga).

13
02 сент. Atsakymas, kurį pateikė Daren Thomas, rugsėjo 2 d. 2010-09-02 18:09 '10, 18:09, 2010-09-02 18:09

Aš pasidalinsiu viena piktnaudžiavimo koncepcija, kurią gavau tą pačią dieną:

 var names = new List<string> {"mercedes", "mazda", "bmw", "fiat", "ferrari"}; var startingWith_M = names.Where(x => x.StartsWith("m")); var startingWith_F = names.Where(x => x.StartsWith("f")); // updating existing list names[0] = "ford"; // Guess what should be printed before continuing print( startingWith_M.ToList() ); print( startingWith_F.ToList() ); 

Numatomas rezultatas

 // I was expecting print( startingWith_M.ToList() ); // mercedes, mazda print( startingWith_F.ToList() ); // fiat, ferrari 

Faktinis rezultatas

 // what printed actualy print( startingWith_M.ToList() ); // mercedes print( startingWith_F.ToList() ); // ford, fiat, ferrari 

Paaiškinimas

Kaip ir kituose atsakymuose, rezultato vertinimas buvo atidėtas iki kvietimo į „ ToList ar panašius skambinimo metodus, pavyzdžiui, „ ToArray .

Todėl šiuo atveju galiu perrašyti kodą kaip:

 var names = new List<string> {"mercedes", "mazda", "bmw", "fiat", "ferrari"}; // updating existing list names[0] = "ford"; // before calling ToList directly var startingWith_M = names.Where(x => x.StartsWith("m")); var startingWith_F = names.Where(x => x.StartsWith("f")); print( startingWith_M.ToList() ); print( startingWith_F.ToList() ); 

Groti arround

https://repl.it/E8Ki/0

8
26 нояб. atsakymas pateiktas 26 lapkričio mėn. 2016-11-26 11:03 '16 at 11:03 2016-11-26 11:03

Be visų pirmiau pateiktų atsakymų, čia yra mano du centai. Be kitų sąrašų, kurie įdiegia IEnumerable tokį ICollection, ArrayList ir tt, yra daug kitų tipų. Todėl, jei turime bet kurio metodo parametrą IEnumerable, funkcijai galime perduoti bet kokius duomenų tipus. Ty mes galime turėti metodą dirbti su abstrakcija, o ne konkrečiu įgyvendinimu.

3
16 июня '17 в 2:22 2017-06-16 02:22 atsakymą pateikė Anantas nuo birželio 16 d. 17:24 2:22 2017-06-16 02:22