В чем различия между FirstOrDefault и SingleOrDefault в LINQ?

«В чем различия между FirstOrDefault и SingleOrDefault в LINQ?» — вопрос из категории C# Core, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

FirstOrDefault и SingleOrDefault — методы расширения LINQ с разной семантикой гарантий относительно количества элементов в результирующей последовательности.

Критерий FirstOrDefault SingleOrDefault
Ожидаемое количество 0 или более (берётся первый) Строго 0 или 1
Поведение при 0 элементов Возвращает default(T) (например, null) Возвращает default(T)
Поведение при 2+ элементах Возвращает первый элемент Выбрасывает InvalidOperationException
Производительность Завершается при нахождении первого элемента Всегда проверяет всю последовательность на наличие второго элемента

Примеры:

// Коллекция с дубликатами
var numbers = new List<int> { 1, 2, 3, 2, 5 };

var firstEven = numbers.FirstOrDefault(x => x % 2 == 0); // 2 (первое чётное)
// Это сработает, хотя чётных чисел несколько.

var singleEven = numbers.SingleOrDefault(x => x % 2 == 0); // InvalidOperationException!
// Исключение, потому что чётных чисел больше одного.

// Корректное использование SingleOrDefault — когда элемент должен быть уникальным
var singleOne = numbers.SingleOrDefault(x => x == 1); // 1 (единственный)
var singleTen = numbers.SingleOrDefault(x => x == 10); // 0 (не найдено)

Когда что использовать:

  • FirstOrDefault — когда вам нужен любой подходящий элемент (например, «найти активного пользователя» — их может быть несколько, но берём первого).
  • SingleOrDefault — когда вы ожидаете строго один или ноль элементов, и наличие дубликатов является ошибкой данных (например, «найти пользователя по уникальному email»).

Совет: Использование SingleOrDefault — это явное утверждение об уникальности. Если есть сомнения, используйте FirstOrDefault.