Aşağıdaki LINQ ifadesi nasıl çalışır?


160

Aşağıdaki LINQ ifadesi nasıl çalışır?

İşte benim kod:

var list = new List<int>{1,2,4,5,6};
var even = list.Where(m => m%2 == 0);
list.Add(8);
foreach (var i in even)
{
    Console.WriteLine(i);
}

Çıktı: 2, 4, 6, 8

Neden olmasın 2, 4, 6?


102
Bir sorgu ifadesinin sonucu, sorgunun yürütülmesi değil bir sorgudur.
Eric Lippert

6
Daha az bilgi için bu sorunun kabul edilen cevabına bakınız .
Daniel

9
Şüphesiz, soruyu gerçekten özetleyen bir başlık düşünebilirsiniz.
Matt Ball

2
Downvotes hakkında tahminim (şimdiye kadar 6, benim değil) soru başlığının iyi bir soru olarak çok genel olduğunu düşünüyorlar. Ancak, yukarı oyların sayısını görmek ve bültende haftanın en önemli sorusu olmak için, çok fazla endişelenmeniz gerektiğini düşünmüyorum.
Abel

Yanıtlar:


235

Çıktı ertelenmiş yürütme2,4,6,8 nedeniyle .

Sorgu, sorgu değişkeni oluşturulduğunda değil, sorgu değişkeni yinelendiğinde yürütülür. Buna ertelenmiş icra denir.

- Suprotim Agarwal, " LINQ'da Derhal Sorgu Yürütülmesine Karşı Ertelenmiş"

Sorgu sonuçlarını önbelleğe almak için yararlı olan Hemen Sorgu Yürütme adı verilen başka bir yürütme vardır . Suprotim Agarwal'dan tekrar:

Tek bir değer üretmeyen bir sorgunun hemen yürütülmesini zorlamak için , bir sorgu veya sorgu değişkeninde ToList(), ToDictionary(), ToArray(), Count(), Average()veya Max()yöntemini çağırabilirsiniz . Bunlar, sonucun bir kopyasını / anlık görüntüsünü oluşturmanıza olanak tanıyan dönüşüm işleçleri olarak adlandırılır ve sorguyu yeniden yürütmeye gerek kalmadan erişim istediğiniz kadar çok sayıdadır.

Çıktının olmasını istiyorsanız 2,4,6, şunu kullanın .ToList():

var list = new List<int>{1,2,4,5,6};
var even = list.Where(m => m%2 == 0).ToList();
list.Add(8);
foreach (var i in even)
 {
    Console.WriteLine(i);
 }

8
Count (), Max (), Avg (), Sum () ve muhtemelen tüm listeyi dikkate alması gereken diğer yöntemler de sorgunun değerlendirilmesine neden olur.
Kenned

1
Sıklıkla, bir yöntem olarak 'filterList ()' yerine 'filterList' ifadesini bir değişken olarak almayı düşündüm. Alışılmadık ve belki de performans açısından kusurlu bir şey yapmak için ilginç bir yöntem olabilir.
Katana314

4
@Sebastian - Daha Kenned yorumuna @ için, .First(), .FirstOrDefault(), .Single()ve .SingleOrDefault()ayrıca sorgunun değerlendirilmesini tetikler.
Scotty.NET

4
30 saniyeden daha kısa bir sürede cevabı nasıl aldığınız şaşırtıcı: D
MC

2
@MC Bu soruyu neden sorduğunuzu bilmiyorum. Bir kerede bütün cevap verilmedi. Birkaç kez düzenlendi.
Atish Dipongkor - MVP

11

Bu, ertelenmiş yürütme nedeniyle oldu, yani ifadenin hesaplanması bir yere ihtiyaç duyuluncaya kadar yürütülmez. Bu, veriler çok büyükse performansı daha iyi hale getirir.


3
Pahalı numaralandırmanızın birden çok kez yürütüldüğü anlamına gelebileceğinden, bunu nüanslayabilirsiniz. Böyle bir durumda performans kaybına bile uğrayabilirsiniz.
Umutsuzluğun Yüz burcu

0

Bunun nedeni lambda ifadenizin ertelenmesi. Foreach döngüsünde yinelemeye başladığınızda sorgu yürütülür.


11
Teknik olarak, yineleyicinin ertelenmiş yürütülmesi , lambda değil .
D Stanley

0

LINQ'dan elde edilen bir IEnumerable <> kullandığınızda, yalnızca bir Enumerator sınıfı oluşturulur ve yineleme yalnızca bir yürüyüşte kullandığınızda başlar.


-1

Bu sonucu ertelenmiş yürütme nedeniyle alıyorsunuz, yani sonuç ilk erişilene kadar değerlendirilmiyor.

Daha net hale getirmek için, snipetinizin sonundaki listeye 10 ekleyin ve tekrar yazdırın, çıktıda 10 almazsınız

     var list = new List<int>{1,2,4,5,6};
    var even = list.Where(m => m%2 == 0).Tolist();
    list.Add(8);
    foreach (var i in even)
    {
        Console.WriteLine(i);
    }
//new*
    list.Add(10);
    foreach (var i in even)
    {
        Console.WriteLine(i);
    }

Bunu gerçekten denedin mi? Çıktıya 10giriyorum.
Mark Hurd

@MarkHurd yes iyi yakalama ekledi .ToList (). yazıyı şimdi düzenledi beklenen çıktı vermelidir. Benim beklentim ifade sadece var ilk kez kullandığınızda değerlendirildi ama her zaman değerlendiriliyor gibi görünüyor
sandeep

Şimdi 8her iki çıktıda da bulunmayacak .
Mark Hurd
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.