Ответ
Оба метода возвращают первый элемент последовательности, но их поведение при пустой коллекции или отсутствии совпадений принципиально различается.
First()
- Возвращает первый элемент, удовлетворяющий необязательному предикату.
- Если результат пуст (последовательность пуста или ни один элемент не соответствует условию), метод выбрасывает
InvalidOperationException. - Используйте, когда наличие элемента гарантировано логикой программы. Исключение в этом случае — это fail-fast механизм, указывающий на ошибку в данных или логике.
FirstOrDefault()
- Возвращает первый элемент или значение по умолчанию для типа элемента, если последовательность пуста или нет совпадений.
- Для ссылочных типов —
null. - Для числовых типов значений —
0. - Для
bool—false. - Для
DateTime—DateTime.MinValue.
- Для ссылочных типов —
- Используйте, когда отсутствие элемента является нормальным, допустимым сценарием, и вы готовы обработать значение по умолчанию.
Практические примеры
var numbers = new List<int> { 1, 2, 3, 4, 5 };
var emptyList = new List<int>();
// First — когда элемент должен быть
int firstNumber = numbers.First(); // 1
int firstEven = numbers.First(n => n % 2 == 0); // 2
// int willThrow = emptyList.First(); // InvalidOperationException!
// FirstOrDefault — когда элемент может отсутствовать
int safeFirst = emptyList.FirstOrDefault(); // 0 (значение по умолчанию для int)
int firstGreaterThanTen = numbers.FirstOrDefault(n => n > 10); // 0 (нет совпадений)
// Работа со ссылочными типами
var users = new List<User>();
User foundUser = users.FirstOrDefault(u => u.Id == 123); // null
if (foundUser != null) {
// Обрабатываем найденного пользователя
}
Рекомендация: Выбор метода — это вопрос семантики. First выражает требование, FirstOrDefault — допущение. Использование First там, где элемент может отсутствовать, маскирует ошибки.