← Назад к вопросам

В чём разница между First и FirstOrDefault в LINQ?

1.0 Junior🔥 241 комментариев
#Entity Framework и ORM#Основы C# и .NET

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между First и FirstOrDefault в LINQ

Основное отличие между методами First и FirstOrDefault в LINQ заключается в их поведении при работе с пустой последовательностью (empty sequence). Это ключевое различие влияет на выбор метода в различных сценариях разработки.

Поведение при отсутствии элементов

  • First(): Если последовательность не содержит элементов (empty), метод выбрасывает исключение System.InvalidOperationException с сообщением "Sequence contains no elements". Это поведение аналогично Single() для пустых коллекций.
  • FirstOrDefault(): Если последовательность пуста, метод возвращает default значение для типа элементов. Для ссылочных типов (например, string, class) это null. Для числовых типов (int, double) — 0. Для boolfalse. Для структур (struct) — экземпляр, где все поля имеют свои default значения.

Синтаксис и использование

Оба метода могут использоваться с или без предиката (условия).

// Пример с коллекцией чисел
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };

// First - без условия
int firstElement = numbers.First(); // Возвращает 1

// First - с условием (предикатом)
int firstEven = numbers.First(n => n % 2 == 0); // Возвращает 2

// FirstOrDefault - без условия
int firstOrDefault = numbers.FirstOrDefault(); // Возвращает 1

// FirstOrDefault - с условием
int firstOrDefaultEven = numbers.FirstOrDefault(n => n % 2 == 0); // Возвращает 2

Сценарии применения

Выбор между методами зависит от логики приложения и ожиданий разработчика:

  • Использовать First():
    *   Когда вы **ожидаете**, что в последовательности есть хотя бы один элемент, и его отсутствие является **ошибкой или исключительной ситуацией**.
    *   Когда необходимо явно сигнализировать о проблеме через исключение (например, в валидации входных данных).
    *   Пример: получение первого активного пользователя из списка, где наличие хотя бы одного активного пользователя является обязательным условием для работы функции.

// Пример, где отсутствие элемента - ошибка
var activeUser = users.First(u => u.IsActive);
// Если активных пользователей нет, будет исключение, что логично для этого сценария
  • Использовать FirstOrDefault():
    *   Когда отсутствие элемента является **нормальным, допустимым состоянием**.
    *   Когда вам нужно безопасно получить элемент или default значение без риска исключения.
    *   Часто используется в сочетании с проверкой на `null` (для ссылочных типов) или на default значение.
    *   Пример: поиск первого товара по названию в каталоге; если товар не найден, возвращается `null`, и это нормально для логики поиска.

// Пример, где отсутствие элемента - допустимая ситуация
var product = products.FirstOrDefault(p => p.Name == "Coffee");
if (product != null)
{
    // Обработка найденного товара
}
else
{
    // Обработка случая "товар не найден"
}

Исключения для First с предикатом

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

List<int> nums = new List<int> { 1, 3, 5 };
var result = nums.First(n => n % 2 == 0); // Выбросит исключение, так нет четных чисел

FirstOrDefault() в аналогичной ситуации просто вернет default значение.

Рекомендации по выбору

  1. First() — это "строгий" метод. Используйте его, когда наличие элемента гарантировано логикой или предыдущими шагами, и его отсутствие должно прерывать выполнение.
  2. FirstOrDefault() — это "безопасный" метод. Используйте его в ситуациях поиска или запросов, где результат может быть пустым, и это часть нормальной workflow.
  3. С точки зрения производительности, разница минимальна. Оба метода выполняют линейный поиск (в случае коллекций, не поддерживающих индексацию), но FirstOrDefault добавляет проверку на пустую последовательность и возвращает default значение без генерации исключения, что может быть чуть менее затратно в случае частых пустых результатов.

Пример в реальном сценарии

Представьте метод, который получает первый заказ пользователя для обработки:

// Сценарий 1: Используем First, если заказ должен существовать
public Order ProcessFirstOrder(int userId)
{
    var order = _repository.GetOrders(userId).First();
    // Если заказов нет, исключение укажет на проблему в данных
    return ProcessOrder(order);
}

// Сценарий 2: Используем FirstOrDefault, если заказ может отсутствовать
public Order TryProcessFirstOrder(int userId)
{
    var order = _repository.GetOrders(userId).FirstOrDefault();
    if (order == null)
    {
        // Логируем или возвращаем статус "нет заказов"
        return null;
    }
    return ProcessOrder(order);
}

В итоге: выбор между First и FirstOrDefault — это выбор между гарантией наличия элемента (с исключением в случае нарушения) и безопасной попыткой получения (с default значением в случае отсутствия). Это решение должно основываться на бизнес-логике и ожидаемом поведении приложения.