Kiedy używać .First i kiedy używać .FirstOrDefault z LINQ?

824

Szukałem dookoła i tak naprawdę nie znalazłem jasnej odpowiedzi na pytanie, kiedy chcesz używać .Firsti kiedy chcesz korzystać .FirstOrDefaultz LINQ.

  • Kiedy chcesz użyć .First? Tylko kiedy chcesz złapać wyjątek, jeśli nie zwrócono żadnych wyników?

    var result = List.Where(x => x == "foo").First();
  • A kiedy chcesz użyć .FirstOrDefault? Kiedy zawsze chcesz mieć domyślny typ, jeśli nie ma rezultatu?

    var result = List.Where(x => x == "foo").FirstOrDefault();
  • A jeśli o to chodzi, co z Take?

    var result = List.Where(x => x == "foo").Take(1);
Metro Smurf
źródło
86
.Firsti .FirstOrDefaultoba przyjmują predykaty jako argumenty, więc var result = List.Where(x => x == "foo").First();można je przepisać jakovar result = List.First(x => x == "foo");
Rian Schmits
59
Nie zapomnij rozważyć Singlei SingleOrDefault. Nienawidzę, kiedy ludzie używają, Firstkiedy naprawdę mają na myśli Single; )
BartoszKP
19
Single lub SingleOrDefault zgłosi wyjątek, jeśli zwróci się więcej niż jeden element! Myślę, że FirstOrDefault jest lepszy w większości powszechnych przypadków!
Eric Draven,
21
Chodzi o to, kiedy oczekujesz wyniku pojedynczego, który powinieneś powiedzieć, a wyjątek wskazuje, że logika się nie powiodła.
NetMage
1
Weź również pod uwagę, że używanie .FirstOrDefault()zawsze daje możliwość rzucenia bardziej znaczącego wyjątku. Jeśli zgłoszony zostanie wyjątek sekwencji i więcej niż jeden .First()w metodzie, może być trudno rozpoznać, która instrukcja jest problemem.
StingyJack,

Odpowiedzi:

807

Użyłbym, First()gdy wiem lub oczekuję, że sekwencja będzie miała co najmniej jeden element. Innymi słowy, gdy jest wyjątkowym zjawiskiem, sekwencja jest pusta.

Użyj, FirstOrDefault()gdy wiesz, że będziesz musiał sprawdzić, czy był element, czy nie. Innymi słowy, gdy jest legalne, aby sekwencja była pusta. Nie należy polegać na obsłudze wyjątków w przypadku czeku. (Jest to zła praktyka i może zaszkodzić wydajności).

Na koniec różnica między First()i Take(1)polega na tym, że First()zwraca sam element, podczas gdy Take(1)zwraca sekwencję elementów, która zawiera dokładnie jeden element.

driis
źródło
4
@driis - wyobrażam sobie, że możemy użyć mantry wyjątkowej wytycznej wyjątku przy wyborze pomiędzy First a FirstOrDefault. Dzięki za jasną odpowiedź.
Metro Smurf
5
Dodam tylko, że jeśli domyślna wartość dla wybranego typu może być prawidłową wartością, na przykład wynikiem może być wartość int 0, to obsługa wyjątku wydaje się najlepszym sposobem na poradzenie sobie z tym .
PeterBelm,
25
Zarysuj to, znalazłem o wiele lepszy sposób, aby to osiągnąć, użyj: DefaultIfEmpty (-1) .First ()
PeterBelm
5
Take nie zwraca dokładnie jednego elementu, zwraca najwyżej jeden element (jeśli podasz 1, oczywiście). Równie dobrze może zwrócić 0 elementów, jeśli sekwencja jest początkowo pusta.
SPIRiT_1984
3
@RoyiNamir, tak w kontekście pytania, gdzie parametrem do przyjęcia jest 1. Zauważyłem również, że w parens bezpośrednio po tym zdaniu.
driis
272

.Firstzgłosi wyjątek, gdy nie ma żadnych wyników. .FirstOrDefaultnie, po prostu zwróci null (typy referencyjne) lub domyślną wartość typu wartości. (np. jak 0w przypadku int.) Pytanie nie dotyczy tego, kiedy chcesz typ domyślny, ale więcej: Czy chcesz obsłużyć wyjątek lub wartość domyślną? Ponieważ wyjątki powinny być wyjątkowe, FirstOrDefaultjest preferowane, gdy nie masz pewności, czy chcesz uzyskać wyniki z zapytania. Gdy logicznie dane powinny tam być, można rozważyć obsługę wyjątków.

Skip()i Take()są zwykle używane podczas konfigurowania stronicowania wyników. (Jak pokazywanie pierwszych 10 wyników, a następnych 10 na następnej stronie itp.)

Mam nadzieję że to pomoże.

Jeroen Landheer
źródło
5
@Jeroen - dobra uwaga na temat lepszych przypadków użycia przy użyciu funkcji Skip / Take.
Metro Smurf
4
+1 za wyjaśnienie, .FirstOrDefaultktóre zwróci null dla typów referencyjnych. Byłem zdezorientowany co do tego, czym byłby „domyślny” obiekt. Ta odpowiedź to wyjaśniła.
Mike Taverne
115

.First()wyrzuci wyjątek, jeśli nie ma zwracanego wiersza, a zamiast tego .FirstOrDefault()zwróci wartość domyślną ( NULLdla wszystkich typów referencji).

Więc jeśli jesteś przygotowany i chcesz poradzić sobie z możliwym wyjątkiem, .First()jest w porządku. Jeśli != nullmimo to wolisz sprawdzić wartość zwracaną , to .FirstOrDefault()jest lepszy wybór.

Ale myślę, że to też trochę osobiste preferencje. Użyj tego, co ma dla ciebie większy sens i lepiej pasuje do twojego stylu kodowania.

marc_s
źródło
66

Pierwszy()

  1. Zwraca pierwszy element sekwencji.
  2. Zgłasza błąd, gdy w wyniku nie ma elementu lub źródło ma wartość NULL.
  3. powinieneś go użyć, jeśli oczekuje się więcej niż jednego elementu i chcesz tylko pierwszy element.

FirstOrDefault ()

  1. Zwraca pierwszy element sekwencji lub wartość domyślną, jeśli nie znaleziono elementu.
  2. Zgłasza błąd Tylko wtedy, gdy źródło ma wartość null.
  3. powinieneś go użyć, jeśli oczekuje się więcej niż jednego elementu i chcesz tylko pierwszy element. Również dobrze, jeśli wynik jest pusty.

Mamy tabelę UserInfos, która zawiera niektóre rekordy, jak pokazano poniżej. Na podstawie poniższej tabeli stworzyłem przykład ...

Tabela informacji o użytkowniku

Jak korzystać z First ()

var result = dc.UserInfos.First(x => x.ID == 1);

Jest tylko jeden rekord, w którym identyfikator == 1. Powinien zwrócić ten rekord
ID: 1 Imię: Manish Nazwisko: Dubey E-mail: [email protected]

var result = dc.UserInfos.First(x => x.FName == "Rahul");   

Istnieje wiele rekordów, w których FName == „Rahul”. Pierwszy rekord powinien zostać zwrócony.
ID: 7 Imię: Rahul Nazwisko: Sharma E-mail: [email protected]

var result = dc.UserInfos.First(x => x.ID ==13);

Brak rekordu o identyfikatorze == 13. Powinien wystąpić błąd.
InvalidOperationException: Sequence nie zawiera elementów

Jak korzystać z FirstOrDefault ()

var result = dc.UserInfos.FirstOrDefault(x => x.ID == 1);

Jest tylko jeden rekord, w którym identyfikator == 1. Powinien zwrócić ten rekord
ID: 1 Imię: Manish Nazwisko: Dubey E-mail: [email protected]

var result = dc.UserInfos.FirstOrDefault(x => x.FName == "Rahul");

Istnieje wiele rekordów, w których FName == „Rahul”. Pierwszy rekord powinien zostać zwrócony.
ID: 7 Imię: Rahul Nazwisko: Sharma E-mail: [email protected]

var result = dc.UserInfos.FirstOrDefault(x => x.ID ==13);

Brak rekordu o identyfikatorze == 13. Zwracana wartość to null

Mam nadzieję, że pomoże ci to zrozumieć, kiedy użyć First()lub FirstOrDefault().

Mukesh Kumar
źródło
4
Moim zdaniem stwierdzenie „Powinien wystąpić błąd”. pod trzecim FirstOrDefault () - przykład wprowadza w błąd.
Jannik
Witaj, dobrze to tłumaczysz, ale jestem trochę zdezorientowany, kiedy otrzymuję dane z przyłączenia, a kiedy identyfikator nie istniał w tabeli kluczy obcych, który z nich jest używany? Obecnie używam First (), ale po przeczytaniu twojej odpowiedzi nie mam pojęcia. Proszę o pomoc
Brijesh Mavani,
20

Przede wszystkim Takejest to zupełnie inna metoda. Zwraca IEnumerable<T>ani jednego T, więc nie ma.

Pomiędzy Firsti FirstOrDefaultpowinieneś użyć, Firstgdy masz pewność, że element istnieje, a jeśli nie, oznacza to błąd.

Nawiasem mówiąc, jeśli twoja sekwencja zawiera default(T)elementy (np. null) I musisz odróżnić bycie pustym od pierwszego elementu null, nie możesz użyć FirstOrDefault.

Mehrdad Afshari
źródło
2
@ Mehrdad - świetne punkty, re: .First zwraca IEnumerable i kiedy nie należy używać FirstOrDefault.
Metro Smurf
15

Pierwszy:

  • Zwraca pierwszy element sekwencji
  • Zgłasza wyjątek: w wyniku nie ma żadnych elementów
  • Użyj, gdy: gdy oczekuje się więcej niż 1 elementu, a chcesz tylko pierwszy

FirstOrDefault:

  • Zwraca pierwszy element sekwencji lub wartość domyślną, jeśli nie znaleziono elementu
  • Zgłasza wyjątek: tylko jeśli źródło ma wartość null
  • Użyj, gdy: gdy oczekuje się więcej niż 1 elementu, a chcesz tylko pierwszy. Również ok może być pusty wynik

Od: http://www.technicaloverload.com/linq-single-vs-singleordefault-vs-first-vs-firstordefault/

użytkownik2051770
źródło
10

Inną różnicą, na którą należy zwrócić uwagę, jest to, że jeśli debugujesz aplikację w środowisku produkcyjnym, możesz nie mieć dostępu do numerów linii, więc określenie, która konkretna .First()instrukcja w metodzie spowodowała wyjątek, może być trudna.

Komunikat o wyjątku nie będzie również zawierał żadnych wyrażeń Lambda, które mogłyby spowodować, że problem będzie trudniejszy do debugowania.

Dlatego zawsze używam, FirstOrDefault()chociaż wiem, że zerowy wpis stanowiłby wyjątkową sytuację.

var customer = context.Customers.FirstOrDefault(i => i.Id == customerId);
if (customer == null)
{
   throw new Exception(string.Format("Can't find customer {0}.", customerId));
}
Kye
źródło
5

Pierwszy()

Gdy wiesz, że wynik zawiera więcej niż 1 oczekiwany element i powinieneś tylko pierwszy element sekwencji.

FirstOrDefault ()

FirstOrDefault () jest tak samo jak First (), z tym wyjątkiem, że jeśli żaden element nie pasuje do określonego warunku, zwraca domyślną wartość podstawowego typu kolekcji ogólnej. Nie zgłasza InvalidOperationException, jeśli nie znaleziono elementu. Ale zbiór elementu lub sekwencji jest zerowy, niż powoduje wyjątek.

Nimesh khatri
źródło
Witaj, dobrze to tłumaczysz, ale jestem trochę zdezorientowany, kiedy otrzymuję dane z przyłączenia, a kiedy identyfikator nie istniał w tabeli kluczy obcych, który z nich jest używany? Obecnie używam First (), ale po przeczytaniu twojej odpowiedzi nie mam pojęcia. Proszę o pomoc
Brijesh Mavani,
4

Ten typ funkcji należy do operatorów elementów. Niektóre przydatne operatory elementów są zdefiniowane poniżej.

  1. First / FirstOrDefault
  2. Last / LastOrDefault
  3. Single / SingleOrDefault

Używamy operatorów elementów, gdy musimy wybrać pojedynczy element z sekwencji na podstawie określonego warunku. Oto przykład.

  List<int> items = new List<int>() { 8, 5, 2, 4, 2, 6, 9, 2, 10 };

Operator First () zwraca pierwszy element sekwencji po spełnieniu warunku. Jeśli żaden element nie zostanie znaleziony, wygeneruje wyjątek.

wynik int = items.Where (item => item == 2) .First ();

Operator FirstOrDefault () zwraca pierwszy element sekwencji po spełnieniu warunku. Jeśli nie zostanie znaleziony żaden element, zwróci domyślną wartość tego typu.

int wynik1 = items.Where (item => item == 2) .FirstOrDefault ();

Sheo Dayal Singh
źródło
dobrze wyjaśnione za pomocą łatwego do zrozumienia przykładu.
Arslan Bhatti
3

Znalazłem stronę internetową, która pojawia się, aby wyjaśnić potrzebę FirstOrDefault
http://thepursuitofalife.com/the-linq-firstordefault-method-and-null-resultsets/
Jeśli nie ma wyników zapytania, i chcesz zadzwonić w pierwszej kolejności () lub Single (), aby uzyskać pojedynczy wiersz ... Otrzymasz wyjątek „Sekwencja nie zawiera elementów”.

Oświadczenie: Nigdy nie korzystałem z LINQ, więc przepraszam, jeśli jest to zupełnie nie na miejscu.

ZERO
źródło
2
someList.First(); // exception if collection is empty.
someList.FirstOrDefault(); // first item or default(Type)

Którego użyć? Powinno to zależeć od logiki biznesowej, a nie lęku przed wyjątkiem / niepowodzeniem programu.

Na przykład jeśli logika biznesowa mówi, że nie możemy mieć zerowych transakcji w żadnym dniu roboczym (Załóżmy). Wtedy nie powinieneś próbować obsługiwać tego scenariusza za pomocą inteligentnego programowania. Zawsze będę używał First () nad taką kolekcją i pozwolę programowi zawieść, jeśli coś innego popsuło logikę biznesową.

Kod:

var transactionsOnWorkingDay = GetTransactionOnLatestWorkingDay();
var justNeedOneToProcess = transactionsOnWorkingDay.First(): //Not FirstOrDefault()

Chciałbym zobaczyć komentarze innych na ten temat.

Manish Basantani
źródło
Wartość domyślna dla typów referencyjnych i zerowalnych to null.
dsa
Szybka porażka jest dobra - jednak w opisanym scenariuszu wolałbym zobaczyć Najpierw, aby się nie powiodła, złapała wyjątek, a następnie zwróciła znaczący błąd. Like catch (InvalidOperationException e) {wyrzuć nowy InvalidOperationException („Nie można mieć zero transakcji w ciągu jednego dnia!”, E)}; Ale tak, użycie domyślnej opcji, aby uniknąć czynienia z prawdziwym problemem logiki biznesowej, jest bardzo złe.
Mathieson
1

Ok, daj mi dwa centy. Pierwszy / pierwszy błąd występuje, gdy używasz drugiego konstruktora. Nie wyjaśnię, co to jest, ale wtedy potencjalnie zawsze używałbyś jednego, ponieważ nie chcesz powodować wyjątku.

person = tmp.FirstOrDefault(new Func<Person, bool>((p) =>
{
    return string.IsNullOrEmpty(p.Relationship);
}));
ariański
źródło
Nie dokładnie. Pierwszy konstruktor jest szeroko stosowany, gdy trzeba pobrać tylko jeden element lub uniknąć błędu kompilacji podczas przypisywania wyniku do wartości, która nie jest tablicą, i masz pewność, że zapytanie zwraca dokładnie jeden wynik. Chociaż użycie drugiego konstruktora może wyglądać szybciej niż użycie dodatkowego .Where () (ponieważ uważasz , że LINQ przestaje oceniać elementy na liście po znalezieniu pierwszego), zawsze zatrzymuje się na pierwszym elemencie
usr-local-ΕΨΗΕΛΩΝ
0

Inni bardzo dobrze opisali różnicę między First()i FirstOrDefault(). Chcę zrobić kolejny krok w interpretacji semantyki tych metod. Moim zdaniem FirstOrDefaultjest często nadużywany. W większości przypadków, gdy filtrujesz dane, możesz oczekiwać odzyskania kolekcji elementów pasujących do warunku logicznego lub pojedynczego unikalnego elementu poprzez jego unikalny identyfikator - taki jak użytkownik, książka, post itp. dlaczego możemy nawet powiedzieć, że FirstOrDefault()jest to zapach kodu, nie dlatego, że coś jest z nim nie tak, ale dlatego, że jest używany zbyt często. Ten post na blogu szczegółowo omawia ten temat. IMO przez większość czasuSingleOrDefault() jest znacznie lepszą alternatywą, więc uważaj na ten błąd i upewnij się, że używasz najbardziej odpowiedniej metody, która jasno odzwierciedla twoją umowę i oczekiwania.

Vasil Kosturski
źródło
-6

linq wiele sposobów na implementację pojedynczego prostego zapytania do kolekcji, po prostu piszemy sprzężenia w sql, filtr może być zastosowany pierwszy lub ostatni w zależności od potrzeb i konieczności.

Oto przykład, w którym możemy znaleźć element z identyfikatorem w kolekcji. Aby dodać więcej na ten temat, metody First, FirstOrDefaultidealnie zwróciłyby to samo, gdy kolekcja ma co najmniej jeden rekord. Jeśli jednak kolekcja może być pusta. następnie Firstpowróci wyjątek ale FirstOrDefaultpowróci nulllub domyślna. Na przykład intzwróci 0. Tak więc korzystanie z takich jest, chociaż mówi się, że jest osobistą preferencją, ale lepiej jest użyć, FirstOrDefaultaby uniknąć obsługi wyjątków. Oto przykład, w którym przeglądamy kolekcję listy transakcji

venkat
źródło