Когда использовать .First и когда использовать .FirstOrDefault с LINQ?

824

Я искал вокруг и не нашел четкого ответа относительно того, когда вы хотите использовать .Firstи когда вы хотите использовать .FirstOrDefaultс LINQ.

  • Когда бы вы хотели использовать .First? Только когда вы захотите перехватить исключение, если результаты не возвращены?

    var result = List.Where(x => x == "foo").First();
  • И когда бы вы хотели использовать .FirstOrDefault? Когда вы всегда хотите тип по умолчанию, если нет результата?

    var result = List.Where(x => x == "foo").FirstOrDefault();
  • И в этом отношении, что относительно Take?

    var result = List.Where(x => x == "foo").Take(1);
Метро Смурф
источник
86
.Firstи .FirstOrDefaultоба принимают предикаты в качестве аргументов, поэтому var result = List.Where(x => x == "foo").First();могут быть переписаны какvar result = List.First(x => x == "foo");
Rian Schmits
59
Не забудьте рассмотреть Singleи SingleOrDefault. Я ненавижу, когда люди используют, Firstкогда они действительно имеют в виду Single; )
BartoszKP
19
Single или SingleOrDefault будут генерировать исключение, если возвращено более одного элемента! Я думаю, что FirstOrDefault лучше в большинстве случаев!
Эрик Дравен,
21
Дело в том, что когда вы ожидаете одного результата, вы должны сказать об этом, а исключение указывает на сбой вашей логики.
NetMage
1
Также учтите, что использование .FirstOrDefault()всегда дает вам возможность создать более значимое исключение. Если выдается исключение последовательности и более одного .First()в методе, может быть трудно определить, какое утверждение является проблемой.
StingyJack

Ответы:

807

Я бы использовал, First()когда я знаю или ожидаю, что последовательность будет иметь хотя бы один элемент. Другими словами, когда это исключительный случай, последовательность пуста.

Используйте, FirstOrDefault()когда вы знаете, что вам нужно будет проверить, был ли элемент или нет. Другими словами, когда допустимо, чтобы последовательность была пустой. Вы не должны полагаться на обработку исключений для проверки. (Это плохая практика и может повредить производительность).

Наконец, разница между First()и Take(1)заключается в том, что First()возвращает сам элемент, а Take(1)возвращает последовательность элементов, которая содержит ровно один элемент.

driis
источник
4
@driis - я полагаю, что мы можем использовать мантру руководящих принципов исключительных ситуаций при выборе между First и FirstOrDefault. Спасибо за четкий ответ.
Метро Смурф
5
Единственное, что я хотел бы добавить, это то, что если значение по умолчанию для выбранного вами типа может быть допустимым значением, например, ваш результат может быть значением int 0, то обработка исключения, кажется, лучший способ обработать это. ,
PeterBelm
25
Поцарапав это, я нашел гораздо более хороший способ сделать это, используя: DefaultIfEmpty (-1) .First ()
PeterBelm
5
Take не возвращает ровно один элемент, оно возвращает не более одного элемента (если вы, конечно, укажите 1). Он также может вернуть 0 элементов, если последовательность изначально пуста.
SPIRiT_1984
3
@RoyiNamir, да, в контексте вопроса, где взять параметр, равный 1. Я также отметил, что в скобках сразу после этого предложения.
Дрис
272

.Firstвыдаст исключение, когда нет результатов. .FirstOrDefaultне будет, он просто вернет либо ноль (ссылочные типы), либо значение по умолчанию для типа значения. (например, как 0для int.) Вопрос здесь не в том, когда вам нужен тип по умолчанию, а в следующем: готовы ли вы обрабатывать исключение или обрабатывать значение по умолчанию? Так как исключения должны быть исключительными, FirstOrDefaultпредпочтительнее, когда вы не уверены, собираетесь ли вы получить результаты из своего запроса. Когда логически данные должны быть там, обработка исключений может быть рассмотрена.

Skip()и Take()обычно используются при настройке подкачки в результатах. (Например, показ первых 10 результатов и следующих 10 на следующей странице и т. Д.)

Надеюсь это поможет.

Йерун Ландхир
источник
5
@Jeroen - хорошее замечание о лучших вариантах использования Skip / Take.
Метро Смурф
4
+1 за объяснение, которое .FirstOrDefaultбудет возвращать ноль для ссылочных типов. Я был озадачен тем, каким будет объект «по умолчанию». Этот ответ прояснил это.
Майк Таверн
115

.First()выдаст исключение, если нет строки для возврата, а вместо этого .FirstOrDefault()вернет значение по умолчанию ( NULLдля всех ссылочных типов).

Так что, если вы готовы и готовы обработать возможное исключение, .First()это нормально. Если вы != nullвсе равно предпочитаете проверять возвращаемое значение , тогда .FirstOrDefault()это ваш лучший выбор.

Но я думаю, это тоже немного личного предпочтения. Используйте то, что имеет больше смысла для вас и лучше соответствует вашему стилю кодирования.

marc_s
источник
66

Первый()

  1. Возвращает первый элемент последовательности.
  2. Выдает ошибку, когда в результате отсутствует элемент или источник равен нулю.
  3. Вы должны использовать его, если ожидается более одного элемента, и вы хотите только первый элемент.

FirstOrDefault ()

  1. Возвращает первый элемент последовательности или значение по умолчанию, если элемент не найден.
  2. Выдает ошибку только если источник нулевой.
  3. Вы должны использовать его, если ожидается более одного элемента, и вы хотите только первый элемент. Также хорошо, если результат пуст.

У нас есть таблица UserInfos, в которой есть несколько записей, как показано ниже. На основе этой таблицы ниже я создал пример ...

Таблица пользовательских данных

Как использовать First ()

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

Существует только одна запись, в которой идентификатор == 1. Должен вернуть
идентификатор этой записи : 1 Имя: Маниш Фамилия: Дубей E-mail: xyz@xyz.com

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

Есть несколько записей, где FName == "Rahul". Первая запись должна быть возвращена.
ID: 7 Имя: Рахул Фамилия: Шарма Электронная почта: xyz1@xyz.com

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

Нет записи с идентификатором == 13. Должна возникнуть ошибка.
InvalidOperationException: последовательность не содержит элементов

Как использовать FirstOrDefault ()

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

Существует только одна запись, в которой идентификатор == 1. Должен вернуть
идентификатор этой записи : 1 Имя: Маниш Фамилия: Дубей E-mail: xyz@xyz.com

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

Есть несколько записей, где FName == "Rahul". Первая запись должна быть возвращена.
ID: 7 Имя: Рахул Фамилия: Шарма Электронная почта: xyz1@xyz.com

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

Нет записи с идентификатором == 13. Возвращаемое значение равно нулю

Надеюсь, это поможет вам понять, когда использовать First()или FirstOrDefault().

Мукеш Кумар
источник
4
На мой взгляд, утверждение «ошибка должна произойти». под третьим FirstOrDefault () - пример вводит в заблуждение.
Янник
Здравствуйте, вы хорошо объясните, но я немного запутался, когда происходит получение данных из соединения, и когда идентификатор не существовал в таблице внешних ключей в то время, какой из них используется? В настоящее время я использую First (), но после прочтения вашего ответа я понятия не имею. Пожалуйста, помогите
Brijesh Mavani
20

Прежде всего, Takeэто совершенно другой метод. Возвращает, IEnumerable<T>а не один T, так что нет.

Между Firstи FirstOrDefault, вы должны использовать, Firstкогда вы уверены, что элемент существует, а если нет, то есть ошибка.

Между прочим, если ваша последовательность содержит default(T)элементы (например null), и вам нужно различать, является ли элемент пустым, а первым - быть null, вы не можете его использовать FirstOrDefault.

Мехрдад Афшари
источник
2
@Mehrdad - замечательные моменты, re: .First возвращает IEnumerable и когда не следует использовать FirstOrDefault.
Метро Смурф
15

Первый:

  • Возвращает первый элемент последовательности
  • Выдает исключение: в результате нет элементов
  • Используйте когда: когда ожидается более 1 элемента, и вы хотите только первый

FirstOrDefault:

  • Возвращает первый элемент последовательности или значение по умолчанию, если элемент не найден
  • Выдает исключение: только если источник нулевой
  • Используйте когда: когда ожидается более 1 элемента, и вы хотите только первый. Также вполне возможно, что результат будет пустым

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

user2051770
источник
10

Еще одно отличие, которое следует отметить, состоит в том, что если вы отлаживаете приложение в производственной среде, у вас может не быть доступа к номерам строк, поэтому определение того, какой конкретный .First()оператор в методе вызвал исключение, может быть затруднено.

Сообщение об исключении также не будет содержать каких-либо лямбда-выражений, которые вы могли бы использовать, что могло бы затруднить отладку.

Вот почему я всегда использую, FirstOrDefault()хотя я знаю, что нулевая запись представляет собой исключительную ситуацию.

var customer = context.Customers.FirstOrDefault(i => i.Id == customerId);
if (customer == null)
{
   throw new Exception(string.Format("Can't find customer {0}.", customerId));
}
Ге
источник
5

Первый()

Когда вы знаете, что результат содержит более 1 ожидаемого элемента, и вы должны только первый элемент последовательности.

FirstOrDefault ()

FirstOrDefault () аналогичен First () за исключением того, что если ни один элемент не соответствует указанному условию, он возвращает значение по умолчанию базового типа универсальной коллекции. Он не выдает InvalidOperationException, если элемент не найден. Но коллекция элемента или последовательности равна нулю, чем исключение.

Нимеш Хатри
источник
Здравствуйте, вы хорошо объясните, но я немного запутался, когда происходит получение данных из соединения, и когда идентификатор не существовал в таблице внешних ключей в то время, какой из них используется? В настоящее время я использую First (), но после прочтения вашего ответа я понятия не имею. Пожалуйста, помогите
Brijesh Mavani
4

Этот тип функции принадлежит элементным операторам. Некоторые полезные операторы элементов определены ниже.

  1. Во-первых / FirstOrDefault
  2. Последняя / LastOrDefault
  3. Одноместный / SingleOrDefault

Мы используем операторы элементов, когда нам нужно выбрать один элемент из последовательности на основе определенного условия. Вот пример.

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

Оператор First () возвращает первый элемент последовательности после выполнения условия. Если элемент не найден, он выдаст исключение.

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

Оператор FirstOrDefault () возвращает первый элемент последовательности после выполнения условия. Если элемент не найден, он вернет значение по умолчанию этого типа.

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

Шео Дайал Сингх
источник
хорошо объяснено на простом для понимания примере.
Арслан Бхатти
3

Я нашел сайт , который apperars объяснить необходимость FirstOrDefault
http://thepursuitofalife.com/the-linq-firstordefault-method-and-null-resultsets/
Если нет результатов в запросе, и вы хотите , чтобы позвонить в первую очередь () или Single (), чтобы получить одну строку ... Вы получите исключение «Последовательность не содержит элементов».

Отказ от ответственности: я никогда не использовал LINQ, поэтому мои извинения, если это далеко от истины.

ЗНАЧЕНИЕ NULL
источник
2
someList.First(); // exception if collection is empty.
someList.FirstOrDefault(); // first item or default(Type)

Какой использовать? Это должно решаться бизнес-логикой, а не боязнью отказа / сбоя программы.

Например, если бизнес-логика говорит, что мы не можем иметь нулевые транзакции в любой рабочий день (просто предположим). Тогда вам не следует пытаться справиться с этим сценарием с помощью какого-то умного программирования. Я всегда буду использовать First () над такой коллекцией, и позволю программе завершиться ошибкой, если что-то еще испортит бизнес-логику.

Код:

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

Я хотел бы видеть другие комментарии по этому поводу.

Маниш Басантани
источник
Значением по умолчанию для ссылочного и обнуляемого типов является null.
DSA
Быстро завершиться неудачей - это хорошо - однако для описанного вами сценария я бы предпочел сначала посмотреть, не получится ли это, поймать исключение и затем вернуть значимую ошибку. Как catch (InvalidOperationException e) {throw new InvalidOperationException ("Не может иметь ноль транзакций за день!", E)}; Но да, использование по умолчанию, чтобы избежать реальной проблемы бизнес-логики, очень плохо.
Мэтисон
1

Хорошо, позвольте мне дать два моих цента. First / Firstordefault для, когда вы используете второй конструктор. Я не буду объяснять, что это такое, но это когда вы потенциально всегда используете один, потому что вы не хотите вызывать исключение.

person = tmp.FirstOrDefault(new Func<Person, bool>((p) =>
{
    return string.IsNullOrEmpty(p.Relationship);
}));
ариец
источник
Не совсем. Первый конструктор широко используется, когда вам нужно извлечь только один элемент или избежать ошибки компиляции при присваивании результата значению, которое не является массивом, и вы уверены, что запрос возвращает ровно один результат. Хотя может показаться, что использовать второй конструктор быстрее, чем использование дополнительного .Where () (поскольку, по вашему мнению, LINQ прекращает оценку элементов в списке после нахождения первого), он всегда останавливается на первом элементе
usr-local-ΕΨΗΕΛΩΝ
0

Другие очень хорошо описали разницу между First()и FirstOrDefault(). Я хочу сделать еще один шаг в интерпретации семантики этих методов. По моему мнению, FirstOrDefaultэто слишком злоупотребляют. В большинстве случаев, когда вы фильтруете данные, вы ожидаете получить коллекцию элементов, соответствующих логическому условию, или один уникальный элемент по его уникальному идентификатору, такой как пользователь, книга, публикация и т. Д. почему мы можем даже сказать, что FirstOrDefault()это запах кода не потому, что с ним что-то не так, а потому, что он используется слишком часто. Этот пост в блоге исследует тему в деталях. ИМО в большинстве случаевSingleOrDefault() это гораздо лучшая альтернатива, поэтому следите за этой ошибкой и убедитесь, что вы используете наиболее подходящий метод, который четко отражает ваш контракт и ожидания.

Василь Костурский
источник
-6

У linq много способов реализовать один простой запрос к коллекциям, просто мы пишем соединения в sql, фильтр может применяться первым или последним в зависимости от необходимости и необходимости.

Вот пример, где мы можем найти элемент с идентификатором в коллекции. Чтобы добавить больше к этому, методы First, в FirstOrDefaultидеале, должны возвращать то же самое, когда в коллекции есть хотя бы одна запись. Если, однако, коллекция может быть пустой. затем Firstвернет исключение, но FirstOrDefaultвернет nullили по умолчанию. Например, intвернет 0. Таким образом, использование такового хотя и считается личным предпочтением, но его лучше использовать, FirstOrDefaultчтобы избежать обработки исключений. вот пример, где мы запускаем коллекцию списка транзакций

Venkat
источник