Temukan () vs. Dimana (). FirstOrDefault ()

161

Saya sering melihat orang menggunakan Where.FirstOrDefault()untuk melakukan pencarian dan mengambil elemen pertama. Kenapa tidak pakai saja Find()? Apakah ada keuntungan bagi yang lain? Saya tidak bisa membedakan.

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();
        }
    }
}
KingOfHypocrites
sumber
45
FWIW, list.FirstOrDefault(x => x == "item3");lebih ringkas daripada menggunakan keduanya .Wheredan .FirstOrDefault.
Kirk Woll
@Kirk, saya kira pertanyaan saya berikutnya adalah mengapa mereka menambahkan temuan sama sekali. Itu tip yang bagus. Satu-satunya hal yang dapat saya pikirkan adalah bahwa FirstOrDefault dapat mengembalikan nilai default yang berbeda selain null. Kalau tidak, itu sepertinya tambahan yang tidak berguna.
KingOfHypocrites
8
Findsebelum LINQ. (itu tersedia di. NET 2.0 dan Anda tidak bisa menggunakan lambdas. Anda dipaksa untuk menggunakan metode normal atau metode anonim)
Kirk Woll

Jawaban:

205

Di mana Findmetode ini IEnumerable<T>? (Pertanyaan retoris.)

The Wheredan FirstOrDefaultmetode yang berlaku terhadap beberapa jenis urutan, termasuk List<T>, T[], Collection<T>, dll urut Setiap yang mengimplementasikan IEnumerable<T>dapat menggunakan metode ini. Findhanya tersedia untuk List<T>. Metode yang umumnya lebih dapat diterapkan, kemudian lebih dapat digunakan kembali dan memiliki dampak yang lebih besar.

Saya kira pertanyaan saya berikutnya adalah mengapa mereka menambahkan temuan sama sekali. Itu tip yang bagus. Satu-satunya hal yang dapat saya pikirkan adalah bahwa FirstOrDefault dapat mengembalikan nilai default yang berbeda selain null. Kalau tidak, itu sepertinya tambahan yang tidak berguna

Findpada List<T>mendahului metode lain. List<T>ditambahkan dengan obat generik di .NET 2.0, dan Findmerupakan bagian dari API untuk kelas itu. Wheredan FirstOrDefaultditambahkan sebagai metode ekstensi untuk IEnumerable<T>dengan Linq, yang merupakan versi NET berikutnya. Saya tidak bisa mengatakan dengan pasti bahwa jika Linq ada dengan rilis 2.0 yang Findtidak akan pernah ditambahkan, tapi itu bisa dibilang kasus untuk banyak fitur lain yang datang di versi NET sebelumnya. Yang dibuat usang atau berlebihan oleh versi yang lebih baru.

Anthony Pegram
sumber
85
Hanya untuk melengkapi: Tidak perlu memanggil Where and First atau FirstOrDefault: First atau FirstOrDefault memungkinkan Anda menentukan predikat pencarian, membuat panggilan Where tidak perlu
Robson Rocha
4
Tetapi Where(condition).FirstOrDefault()mengoptimalkan setidaknya juga dan kadang-kadang lebih baik daripada FirstOrDefault(condition)sendiri. Kami selalu menggunakan Where()untuk mendapatkan peningkatan kinerja saat tersedia.
Suncat2000
7
@ Suncat2000 tolong berikan contoh
Konstantin Salavatov
2
@ Suncat2000 Anda menggunakan Linq karena kekuatan ekspresifnya dan ingin menulis kode deklaratif. Anda tidak perlu khawatir dengan perbaikan mikro tersebut, yang juga dapat berubah dalam implementasi di masa mendatang. Juga, jangan optimalkan terlalu dini
Piotr Falkowski
50

Saya baru tahu hari ini, melakukan beberapa tes pada daftar objek 80K dan menemukan bahwa Find()bisa hingga 1000% lebih cepat daripada menggunakan Wheredengan FirstOrDefault(). Saya tidak tahu itu sampai menguji timer sebelum dan sesudah semua. Terkadang itu adalah waktu yang sama, jika tidak lebih cepat.

digiben
sumber
6
Apakah Anda mencobanya dengan Where AND FirstOrDefault? Jika Anda mungkin mencobanya hanya dengan FirstOrDefault dan lihat apakah Find () masih lebih baik.
MVCKarl
5
Kedengarannya seperti Anda tidak mematerialisasi hasil dengan .ToList()atau .ToArray()untuk benar-benar melakukan kueri.
Andrew Morton
4
Itu karena Findmemanfaatkan kunci utama (karenanya indeks), sedangkan Wherekueri sql sederhana
percebus
4
Pada EF6, Find dan FirstOrDefault keduanya menghasilkan pernyataan SQL yang persis sama. Anda dapat melihat SQL di aplikasi konsol dengan melakukan context.Database.Log = Console.Write; Contoh yang ditempatkan menggunakan "Cari" dalam memori terhadap daftar string, tidak bertentangan dengan DB dengan kunci utama. Mungkin terjemahan pernyataan klausa Temukan - yang menghilangkan kebutuhan untuk melakukan penguraian ekspresi lambda adalah alasan untuk peningkatan kinerja dalam kasus ini. Terhadap database saya ragu Anda akan melihat perbedaan dalam situasi RL ... Saya juga bertanya-tanya apakah itu diuji menggunakan Temukan pertama, bukan yang kedua ...
C.Daftar
2
Nah, peningkatan kinerja ini adalah karena find () memeriksa cache untuk objek sebelum memukul DB sedangkan di mana () selalu pergi DB untuk mendapatkan objek
Gaurav
35

Ada perbedaan yang sangat penting jika sumber data adalah Entity Framework: Findakan menemukan entitas dalam status 'tambah' yang belum bertahan, tetapi Wheretidak akan. Ini dengan desain.

Pucat
sumber
1

selain Anthony menjawab Where()kunjungan melalui semua catatan dan kemudian kembali hasil (s) sementara Find()tidak perlu menelusuri semua catatan jika predikat cocok dengan predikat yang diberikan.

jadi katakanlah Anda memiliki Daftar kelas Uji memiliki iddan nameproperti.

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

Akan memberikan hasil 2, dan hanya 2 kunjungan yang diperlukan untuk memberikan hasil, tetapi jika Anda menggunakan Where().FirstOrDefault()kami akan mengunjungi semua catatan dan kemudian kami mendapatkan hasil.

Jadi, ketika Anda tahu Anda hanya ingin hasil pertama dari catatan dalam koleksi Find()akan lebih cocokWhere().FirtorDefault();

M Muneeb Ijaz
sumber
4
tetapi jika Anda menggunakan Where (). FirstOrDefault () kami akan mengunjungi semua catatan dan kemudian kami mendapatkan hasil. Nggak. FirstOrDefaultakan 'menggembungkan' rantai dan berhenti menghitung semuanya. Saya menggunakan istilah 'bubble-up' karena kurangnya ekspresi yang lebih baik, karena sebenarnya setiap pemilih / predikat akan diteruskan ke yang berikutnya, sehingga metode terakhir dalam rantai sebenarnya melakukan pekerjaan terlebih dahulu.
Silvermind
1

Wow saya baru saja menonton tutorial EF dari MicrosofToolbox hari ini di Youtube. Dia memang mengatakan tentang menggunakan Find () dan FirstOrDefault (kondisi) dalam kueri dan Find () akan mencari data yang telah Anda lakukan sesuatu pada objek itu (menambah atau mengedit atau menghapus - tetapi belum disimpan ke dalam database) sementara itu FirstOrDefault hanya akan cari apa yang sudah disimpan

nguyen khanh
sumber
-1

Find()adalah setara IEnumerable dari a FirstOrDefault(). Anda tidak harus rantai keduanya. Dimana () dengan .FirstOrDefault()karena .Where()melewati seluruh array dan kemudian akan beralih melalui daftar itu untuk menemukan item pertama. Anda menghemat banyak waktu dengan menempatkan predikat pencarian Anda dalam FirstOrDefault()metode ini.

Juga, saya mendorong Anda untuk membaca pertanyaan yang ditautkan ke utas ini untuk mengetahui lebih banyak tentang kinerja yang lebih baik dalam menggunakan .Find()skenario spesifik Performance of Find () vs FirstOrDefault ()

Pukulan cemeti
sumber
Ini adalah duplikat dari jawaban di atas milik Anda. Juga, lihat komentar Silvermind tentang jawaban itu.
carlin.scott