() Ve Nerede () ile karşılaşır. FirstOrDefault ()


161

Sıklıkla Where.FirstOrDefault()bir arama yapmak ve ilk öğeyi almak için kullanan insanlar görüyorum . Neden sadece kullanmıyorsunuz Find()? Diğerine bir avantaj var mı? Bir fark söyleyemedim.

namespace LinqFindVsWhere
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> list = new List<string>();
            list.AddRange(new string[]
            {
                "item1",
                "item2",
                "item3",
                "item4"
            });

            string item2 = list.Find(x => x == "item2");
            Console.WriteLine(item2 == null ? "not found" : "found");
            string item3 = list.Where(x => x == "item3").FirstOrDefault();
            Console.WriteLine(item3 == null ? "not found" : "found");
            Console.ReadKey();
        }
    }
}

45
FWIW, ve list.FirstOrDefault(x => x == "item3");kullanmaktan daha özlüdür . .Where.FirstOrDefault
Kirk Woll

@Kirk, sanırım bir sonraki sorumu bulmayı neden eklediler? Bu iyi bir ipucu. Aklıma gelen tek şey, FirstOrDefault null dışında farklı bir varsayılan değer döndürebilir olmasıdır. Aksi takdirde anlamsız bir ekleme gibi görünüyor.
KingOfHococrites

8
FindLINQ'dan önce gelir. (.NET 2.0'da mevcuttu ve lambdas kullanamazsınız. Normal yöntemleri veya anonim yöntemleri kullanmak zorunda
kaldınız

Yanıtlar:


205

FindYöntem nerede IEnumerable<T>? (Retorik soru.)

WhereVe FirstOrDefaultyöntemler de dahil olmak üzere birçok sekans türlü karşı uygulanabilir List<T>, T[], Collection<T>uygular bu gibi herhangi bir sekans IEnumerable<T>, bu yöntemleri kullanabilir. Findyalnızca List<T>. Genellikle daha uygulanabilir olan yöntemler daha sonra tekrar kullanılabilir ve daha büyük bir etkiye sahiptir.

Sanırım bir sonraki sorum neden bulmayı hiç eklediler? Bu iyi bir ipucu. Düşünebildiğim tek şey, FirstOrDefault'un null dışında farklı bir varsayılan değer döndürebilmesidir. Aksi takdirde anlamsız bir ekleme gibi görünüyor

Findüzerinde List<T>eskidir diğer yöntemler. List<T>.NET 2.0'da jeneriklerle birlikte eklendi ve Findsöz konusu sınıfın API'sının bir parçasıydı. Whereve daha sonraki bir .NET sürümü olan Linq FirstOrDefaultiçin uzantı yöntemleri olarak eklenmiştir IEnumerable<T>. Linq'in Findasla eklenmeyecek 2.0 sürümü ile mevcut olduğunu kesin olarak söyleyemem , ancak muhtemelen daha önceki sürümlerde eski veya gereksiz hale getirilen önceki .NET sürümlerinde gelen diğer birçok özellik için durum böyle.


85
Sadece tamamlamak için: Where ve First veya FirstOrDefault'u çağırmanıza gerek yoktur: First veya FirstOrDefault, bir arama yüklemesi belirtmenize izin verir, Where çağrısını gereksiz kılar
Robson Rocha

4
Ancak Where(condition).FirstOrDefault()en azından optimize eder ve bazen FirstOrDefault(condition)yalnız kalmaktan daha iyidir . Mümkün olduğunda her zaman Where()gelişmiş performansı elde etmek için kullanırız.
Suncat2000

7
@ Suncat2000 lütfen bir örnek veriniz
Konstantin Salavatov

2
@ Suncat2000 Etkileyici gücü nedeniyle Linq kullanıyorsunuz ve bildirim kodu yazmak istiyorsunuz. Gelecekteki uygulamalarda da değişebilen bu tür mikro iyileştirmelerle ilgilenmemelisiniz. Ayrıca, çok erken optimizasyon yapmayın
Piotr Falkowski

50

Bugün öğrendim, 80K nesneleri listesinde bazı testler yaptım ve bununla birlikte Find()kullanmaktan% 1000 daha hızlı olabileceğini buldum . Her şeyden önce ve sonra bir zamanlayıcıyı test edene kadar bunu bilmiyordum. Bazen aynı zamandı, aksi takdirde daha hızlıydı. WhereFirstOrDefault()


6
Where AND FirstOrDefault ile denediniz mi? Belki de sadece FirstOrDefault ile denediyseniz ve Find () 'ın hala daha iyi olup olmadığına bakın.
MVCKarl

5
Bu, sonucu bir .ToList()veya .ToArray()ile gerçekten gerçekleştirmediğiniz gibi görünüyor.
Andrew Morton

4
Bunun nedeni Find, birincil anahtarları (dolayısıyla dizinler) kullanmasıdır, oysa Wheredüz bir sql sorgusu
percebus

4
EF6'dan itibaren, Find ve FirstOrDefault her ikisi de tamamen aynı SQL ifadelerini oluşturur. Context.Database.Log = Console.Write yaparak bir konsol uygulamasında SQL görebilirsiniz; Yerleştirilen örnek, birincil anahtarları olan bir DB'ye karşı değil, bir dize listesine karşı bellek içi "Bul" kullanıyor. Belki de lambda ifadesi ayrıştırma yapma ihtiyacını ihmal eden Bul maddesinin ifade çevirisi, bu durumda performans iyileştirmesinin sebebidir. Bir veritabanına karşı RL durumlarında bir fark fark
edeceğinizden şüpheliyim

2
Bu performans iyileştirmesi, DB'ye çarpmadan önce find () nesnesini önbellekte kontrol ederken, () her zaman nesne almak için DB'ye gitmektir
Gaurav

35

Verilerin kaynağı Varlık Çerçevesi ise çok önemli bir fark vardır: Find'eklenmiş' durumda henüz devam etmeyen, ancak Whereolmayacak varlıkları bulur . Bu tasarım gereğidir.



1

Anthony yanı sıra Where()tüm kayıtları aracılığıyla ziyareti cevap ve daha sonra sonuçları belirtilen Find()yüklem ile maç eğer tüm kayıtlar arasında geçiş yapmak gerek yok iade sonuçları .

Diyelim ki Test sınıfı sınıfına sahip idve nameözellikleri var.

 List<Test> tests = new List<Test>();
 tests.Add(new Test() { Id = 1, Name = "name1" });
 tests.Add(new Test() { Id = 2, Name = "name2" });
 tests.Add(new Test() { Id = 3, Name = "name3" });
 tests.Add(new Test() { Id = 4, Name = "name2" }); 
 var r = tests.Find(p => p.Name == "name2");
 Console.WriteLine(r.Id);

Çıktı verecek 2ve sadece 2 ziyaret Sonuç vermek için gerekli bul, ancak kullanırsanız Where().FirstOrDefault()tüm kayıtları ziyaret edeceğiz ve sonra sonuç alıyoruz.

Yani, bile bile sadece koleksiyonunda kayıtlarından ilk sonucu istediğiniz Find()sonra daha uygun olacaktırWhere().FirtorDefault();


4
ancak Where (). FirstOrDefault () kullanırsanız, tüm kayıtları ziyaret edeceğiz ve sonuç alacağız. Hayır! FirstOrDefaultzinciri 'kabarcıklı' hale getirecek ve her şeyi numaralandırmayı bırakacaktır. Daha iyi bir ifade eksikliği için 'kabarcıklı' terimini kullanıyorum, çünkü aslında her seçici / yüklem bir sonrakine geçecek, bu yüzden zincirdeki son yöntem aslında önce iş yapıyor.
Silvermind

1

Vay be sadece YouTube'da MicrosofToolbox'tan EF eğitimini izliyorum. Sorguda Find () ve FirstOrDefault (koşul) kullanma hakkında bir şey söyledi ve Find () bu nesne üzerinde bir şey gerçekleştirdiğiniz verileri arayacaktır (ekleme veya düzenleme veya silme - ancak henüz veritabanına kaydedilmemiş) bu arada FirstOrDefault sadece zaten kaydedilmiş olanları ara


-1

Find()a'nın IEnumerable eşdeğeridir FirstOrDefault(). Her iki .Where () ile zincirleme yapmamalısınız .FirstOrDefault()çünkü .Where()tüm dizi boyunca ilerler ve ardından ilk öğeyi bulmak için bu liste boyunca yinelenir. Arama FirstOrDefault()yönteminizi yönteme koyarak inanılmaz bir zaman kazanırsınız .

Ayrıca, Find of Performance () ve FirstOrDefault () ile ilgili.Find() belirli senaryolarda daha iyi performanslar hakkında daha fazla bilgi edinmek için bu konuyla ilgili soruyu okumanızı öneririz.


Bu, cevabının üstündeki cevabın bir kopyası. Ayrıca, Silvermind'in bu cevap hakkındaki yorumuna bakın.
carlin.scott
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.