IEnumerable vs List - ne kullanılır? Nasıl çalışıyorlar?

Sayaçların nasıl çalıştığı ve LINQ hakkında bazı şüphelerim var. Bu iki basit seçeneği göz önünde bulundurun:

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

veya

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

Kaynak nesnelerimin adlarını daha genel bir örnek gibi görünmesi için değiştirdim. İsteğin kendisi o kadar önemli değil. Sormak istiyorum:

 foreach (Animal animal in sel) {  } 
  • IEnumerable kullandığımda, sel ile hata ayıklayıp kontrol ettiğimde, ki bu durumda IEnumerable olduğunu fark ettim, birkaç ilginç üyeye sahip: "internal", "external", "innerKeySelector" ve "outerKeySelector" 2 delege gibi görünüyor. "İç" üyenin içinde "Hayvan" örnekleri yoktur, aksine benim için çok garip olan "Türler" örnekleri de vardır. "Dış" öğe "Hayvanlar" örneklerini içerir. İki delegenin neyin girip neyin çıkacağına karar verdiğine inanıyorum?

  • "Farklı" kullanırsam, "iç" in 6 öğe içerdiğini (bu yalnızca 2 Farklı olduğu için yanlış), ancak "dış" öğesinin doğru değerleri içerdiğini fark ettim. Yine, muhtemelen yetki verilmiş yöntemler bunu belirler, ancak bu IEnumerable hakkında bildiğimden biraz daha fazla.

  • En önemlisi, iki seçenekten hangisi performansta en iyisidir?

Kötü bir listeyi .ToList() ile dönüştürme?

Ya da belki doğrudan numaralandırıcı kullanın?

Yapabiliyorsanız, lütfen IEnumerable'ın bu kullanımını açıklayan bağlantıları biraz açıklayın veya bırakın.

511
02 сент. Akson 02 Eylül'e ayarlandı . 2010-09-02 18:05 '10, 18:05 2010-09-02 18:05
@ 9 cevap

IEnumerable , davranışı açıklar ve Liste bu davranışın uygulanmasıdır. IEnumerable kullandığınızda, derleyiciye işi daha uzun süre erteleme, belki de yol boyunca optimizasyon yapma olanağı sunarsınız. ToList () kullanıyorsanız, derleyiciyi sonuçları derhal doğrulaması için zorlarsınız.

Ne zaman LINQ ifadeleri "eklersem", IEnumerable kullanırım, çünkü yalnızca davranışı tanımlayarak, LINQ'ya tahmini erteleme ve muhtemelen programı optimize etme fırsatı veririm. LINQ, listelenene kadar bir veritabanı sorgusu için nasıl SQL üretmediğini hatırlıyor musunuz? Bunu düşünün:

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

Şimdi kaynak örneği ("AllSpotted") ve bazı filtreleri seçen bir yönteminiz var. Şimdi bunu yapabilirsiniz:

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

Yani Listeyi IEnumerable üzerinden kullanmak daha mı hızlı? Yalnızca isteğin birden fazla kez yürütülmesini önlemek istiyorsanız. Ama genel olarak daha iyi mi? Yukarıdaki örnekte, Leoparlar ve Sırtlanlar her biri tek SQL sorgularına dönüştürülür ve veritabanı yalnızca değeri olan satırları döndürür. Fakat eğer listeyi AllSpotted() dan AllSpotted() , veritabanı yavaş çalışabilir çünkü veritabanı gerçekte olduğundan çok daha fazla veri döndürebilir ve istemcide filtreleme döngüleri harcarız.

İsteğinizin listeye dönüşümünü sonuna kadar ertelemek programda daha iyi olabilir, bu yüzden bir kereden fazla Leopards ve Sırtlanlar arasında listeye gideceksem, şunları yaparım:

 List<Animals> Leopards = Feline(AllSpotted()).ToList(); List<Animals> Hyenas = Canine(AllSpotted()).ToList(); 
576
02 сент. Cevap C. Lawrence Wenham tarafından verildi 02 Eylül. 2010-09-02 18:36 '10, 18:36 2010-09-02 18:36

IEnumerable uygulayan sınıf, foreach sözdiziminin kullanılmasına izin verir.

Temel olarak, koleksiyondaki bir sonraki öğeyi elde etmenin bir yolu var. Koleksiyonun tamamının hafızada olması gerekmiyor ve içinde kaç element olduğunu bilmiyor, foreach sonraki elemanı bitinceye kadar almaya devam ediyor.

Bu, belirli koşullar altında, örneğin, satırları işlemeye başlamadan önce her şeyi belleğe kopyalamak istemediğiniz büyük bir veritabanı tablosunda çok faydalı olabilir.

List artık IEnumerable uygulamaktadır, ancak bellekteki koleksiyonun tamamını temsil etmektedir. IEnumerable varsa ve .ToList() , bellekteki enum içeriğiyle yeni bir liste oluşturursunuz.

border=0

Linq ifadeniz bir numaralandırma döndürür ve varsayılan olarak ifade, foreach ile birlikte kullanıldığında yürütülür. IEnumerable linq deyimi foreach yinelemede çalıştırılır, ancak .ToList() ile daha hızlı yinelemeye .ToList() .

İşte demek istediğim:

 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 сент. Cevap Keith 02 Eylül tarafından verilmektedir. 2010-09-02 18:24 '10, 18:24 2010-09-02 18:24

Yazılan çok güzel bir makale var: Claudio Bernasconi TechBlog burada: Ne zaman IEnumerable, ICollection, IList ve List kullanılır

Script ve özelliklerle ilgili bazı önemli noktalar:

2019

91
04 июня '15 в 17:07 2015-06-04 17:07 Cevap rubStackOverflow tarafından 04 Haziran '15 te 17:07 2015-06-04 17:07

En önemli şey Linq kullanarak isteğin derhal bir puan almadığını anlamaktır. Tüm garip delegelerin yaptığı IEnumerable<T> bir sonucu olarak yalnızca yinelemenin bir parçası olarak çalışır.

Bu nedenle, ilk örnek ToList çağırarak ve sorgunun sonuçlarını listeye yerleştirerek sorguyu hemen değerlendirir.
İkinci örnek, sorguyu daha sonra çalıştırmak için gereken tüm bilgileri içeren bir IEnumerable<T> değerini döndürür.

Performans açısından, cevap bağlıdır. Sonuçların hemen değerlendirilmesine ihtiyacınız varsa (örneğin, daha sonra talep ettiğiniz mutasyona uğramış yapılarsınız veya IEnumerable<T> üzerinde yinelemenin uzun sürmesini istemiyorsanız) listeyi kullanın. Aksi takdirde, IEnumerable<T> kullanın. Varsayılan olarak, ikinci örnekte isteğe bağlı bir tahmin kullanılmalıdır, çünkü sonuçları listede saklamak için belirli nedenler olmadıkça genellikle daha az bellek kullanılır.

63
02 сент. Cevap thecoop tarafından verildi 02 Eyl 2010-09-02 18:08 '10, 18:08 2010-09-02 18:08

Hiç kimse bir anahtar farktan söz etmedi, soruyu ironik bir şekilde cevapladı, kopyalandığı gibi kapattı.

IEnumerable yalnızca okunur, ancak Liste değil.

Liste ile IEnumerable Arasındaki Pratik Fark bölümüne bakınız .

55
09 дек. Cevap CAD bloke 09 Aralık verilir. 2014-12-09 11:30 '14, 11:30 2014-12-09 11:30

IEnumerable'ın avantajı ertelenmiş uygulamalardır (genellikle veritabanlarıyla). Sorgu, verileri gerçekten döngülendirene kadar yürütülmez. Bu, ihtiyaç duyulana kadar bekleyen bir istektir (aka tembel yükleme).

Eğer ToList'i ararsanız, talep etmek istediğim gibi yürütülür veya "somutlaştırılır".

Her ikisi için de artıları ve eksileri var. ToList'i ararsanız, isteğin ne zaman gerçekleştirileceğine ilişkin bazı sırları silebilirsiniz. IEnumerable'a bağlı kalırsanız, programın ihtiyaç duyulana kadar çalışmaması avantajını elde edersiniz.

33
02 сент. Cevap Matt Sherman 02 eylül. 2010-09-02 18:13 '10, 18:13 2010-09-02 18:13

Tek yapmak istediğiniz şeyleri listelemekse IEnumerable kullanın.

Ancak, listelenen kaynak koleksiyonunu değiştirmenin tehlikeli bir işlem olduğuna dikkat edin - bu durumda, önce ToList istersiniz. Bu, bellekteki her öğe için yeni bir liste öğesi oluşturacak, bir IEnumerable listeleyecek ve bu nedenle, yalnızca bir kez listelerseniz daha az etkili olacak, ancak daha güvenli ve bazen List yöntemleri kullanışlıdır (örneğin, rastgele erişime sahip).

13
02 сент. Tarafından cevaplandı Daren Thomas tarafından 02 Eylül. 2010-09-02 18:09 '10, 18:09 2010-09-02 18:09

Aynı gün aldığım yanlış kullanılan bir kavramı paylaşacağım:

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

Beklenen Sonuç

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

Gerçek sonuç

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

açıklama

Diğer yanıtlarda olduğu gibi, sonucun değerlendirilmesi ToArray çağrılara veya benzer arama yöntemlerine, örneğin ToArray .

Bu nedenle, bu durumda kodu yeniden yazabilirim:

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

Oyun etrafında

https://repl.it/E8Ki/0

8
26 нояб. Cevap 26 Kasım'da verildi. 2016-11-26 11:03 '16, 11:03 2016-11-26 11:03

Yukarıdaki tüm cevaplara ek olarak, işte iki sentim. Listede ICnection, ArrayList vb. Gibi sayısız IE uygulaması yapılabilir. Bu nedenle, eğer herhangi bir yöntemin parametresi olarak IEnumerable varsa, herhangi bir veri tipini işleve aktarabiliriz. yani Herhangi bir uygulama ile değil soyutlama ile çalışmak için bir yöntemimiz olabilir.

3
16 июня '17 в 2:22 2017-06-16 02:22 Cevap 16 Haziran 17'de Ananth tarafından 2:22 2017-06-16 02:22

ilgili diğer sorular veya bir soru sorun