Wiele osób nie zna różnicy pomiędzy Single(), SingleOrDefault(), First() oraz FirstOrDefault(). Poniżej, mam nadzieje w czytelny sposób, zostały przedstawione różnice pomiędzy nimi:

Single() SingleOrDefault() First() FirstOrDefault()
Opis Zwraca jeden konkretny element Zwraca jeden konkretny element lub wartość domyślną jeżeli element nie został odnaleziony Zwraca pierwszy element Zwraca pierwszy element lub wartość domyślną jeżeli żaden element nie został odnaleziony
Wyjątek, gdy… Nie odnaleziono elementu bądź więcej niż jeden element Znaleziono więcej niż jeden element Nie ma żadnego elementu Tylko, jeżeli kolekcja jest pusta (wszystkie z nich zwracają wyjątek)
Kiedy używać? Gdy oczekujemy dokładnie 1 rezultatu; nie 0 lub więcej niż 1 Gdy oczekujemy 0 lub 1 elementów Gdy oczekujemy więcej niż jednego elementu, ale chcemy zwrócić dokładnie jeden element Gdy oczekujemy więcej niż 1 elementu, ale chcemy zwrócić dokładnie jeden element. Rezultat w tym wypadku może być również pusty

Przykłady użycia

W pierwszej kolejności przygotujemy kolekcję na której będziemy sprawdzać różne przypadki użycia. Nasza kolekcja będzie skadała się z następujących danych:

  • Tylko jeden samochód o Id równym 1; CarId = 1;
  • Podwójny wpis dotyczący jednego modelu auta: Model = 100;
  • Brak definicji samochodu o Id równym 10.
Poniżej nasza kolekcja:
carList.Add(new Car() { CarId = 1, Brand = "Audi", Model = "100" });
carList.Add(new Car() { CarId = 2, Brand = "Audi", Model = "A1" });
carList.Add(new Car() { CarId = 3, Brand = "Audi", Model = "A2" });
carList.Add(new Car() { CarId = 4, Brand = "Audi", Model = "A3" });
carList.Add(new Car() { CarId = 5, Brand = "Audi", Model = "A4" });
carList.Add(new Car() { CarId = 6, Brand = "Audi", Model = "A5" });
carList.Add(new Car() { CarId = 7, Brand = "Audi", Model = "100" });
carList.Add(new Car() { CarId = 8, Brand = "Audi", Model = "A7" });
carList.Add(new Car() { CarId = 9, Brand = "Audi", Model = "A8" });

Single()

// W kolekcji mamy tylko jeden rekord od CarId = 1.
// Zwrócimy dokładnie ten rekord
var test1 = carList.Single(a => a.CarId == 1);
// W kolekcji mamy dwa modele Audi o które pytamy
// Powinniśmy zobaczyć błąd:
// Sequence contains more than one matching element
var test2 = carList.Single(a => a.Model == "100");
// W kolekcji nie mamy rekordu o CarId = 10
// Powinniśmy zobaczyć błąd:
// Sequence contains no matching element
var test3 = carList.Single(a => a.CarId == 10);
SingleOrDefault()
// W kolekcji mamy tylko jeden rekord od CarId = 1.
// Zwrócimy dokładnie ten rekord
var test1 = carList.SingleOrDefault(a => a.CarId == 1);
// W kolekcji mamy dwa modele Audi o które pytamy
// Powinniśmy zobaczyć błąd:
// Sequence contains more than one matching element
var test2 = carList.SingleOrDefault(a => a.Model == "100");
// W kolekcji nie mamy rekordu o CarId = 10
// Powinna zostać zwrócona wartość domyślną: null
var test3 = carList.SingleOrDefault(a => a.CarId == 10);
First()
// W kolekcji mamy zapisane dwa modele Audi 100
// W pierwszej kolejności sortujemy malejąco a następnie szukamy naszego modelu
// Powinien zostać zwrócony model o CarId = 7
var test1 = carList.OrderByDescending(a => a.CarId).First(a => a.Model == "100");
// W kolekcji nie mamy rekordu o CarId = 10
// Powinniśmy zobaczyć błąd:
// Sequence contains no matching element            
var test2 = carList.First(a => a.CarId == 10);
FirstOrDefault()
// W kolekcji mamy zapisane dwa modele Audi 100
// W pierwszej kolejności sortujemy malejąco a następnie szukamy naszego modelu
// Powinien zostać zwrócony model o CarId = 7
var test1 = carList.OrderByDescending(a => a.CarId).FirstOrDefault(a => a.Model == "100");
// W kolekcji nie mamy rekordu o CarId = 10
// Powinna zostać zwrócona wartość domyślną: null
var test2 = carList.FirstOrDefault(a => a.CarId == 10);
Komplenty kod
using System.Collections.Generic;
using System.Linq;
namespace Single_SingleOrDefault_First_FirstOrDefault
{
    class Program
    {
        static List<Car> carList;
        static void Main(string[] args)
        {
            // Wypełniamy kolekcję danymi
            // Proszę odkomentować metodę, którą chcecie przetestować
            PrepareCollectionOfData();
            // SingleTestCase();
            // SingleOrDefaultTestCase();
            // FirstTestCase();
            // FirstOfDefaultTestCase();
        }
        private static void FirstOfDefaultTestCase()
        {
            // W kolekcji mamy zapisane dwa modele Audi 100
            // W pierwszej kolejności sortujemy malejąco a następnie szukamy naszego modelu
            // Powinien zostać zwrócony model o CarId = 7
            var test1 = carList.OrderByDescending(a => a.CarId).FirstOrDefault(a => a.Model == "100");
            // W kolekcji nie mamy rekordu o CarId = 10
            // Powinna zostać zwrócona wartość domyślną: null
            var test2 = carList.FirstOrDefault(a => a.CarId == 10);
        }
        private static void FirstTestCase()
        {
            // W kolekcji mamy zapisane dwa modele Audi 100
            // W pierwszej kolejności sortujemy malejąco a następnie szukamy naszego modelu
            // Powinien zostać zwrócony model o CarId = 7
            var test1 = carList.OrderByDescending(a => a.CarId).First(a => a.Model == "100");
            // W kolekcji nie mamy rekordu o CarId = 10
            // Powinniśmy zobaczyć błąd:
            // Sequence contains no matching element
            var test2 = carList.First(a => a.CarId == 10);
        }
        private static void SingleOrDefaultTestCase()
        {
            // W kolekcji mamy tylko jeden rekord od CarId = 1.
            // Zwrócimy dokładnie ten rekord
            var test1 = carList.SingleOrDefault(a => a.CarId == 1);
            // W kolekcji mamy dwa modele Audi w które pytamy
            // Powinniśmy zobaczyć błąd:
            // Sequence contains more than one matching element
            var test2 = carList.SingleOrDefault(a => a.Model == "100");
            // W kolekcji nie mamy rekordu o CarId = 10
            // Powinna zostać zwrócona wartość domyślną: null
            var test3 = carList.SingleOrDefault(a => a.CarId == 10);
        }
        private static void SingleTestCase()
        {
            // W kolekcji mamy tylko jeden rekord od CarId = 1.
            // Zwrócimy dokładnie ten rekord
            var test1 = carList.Single(a => a.CarId == 1);
            // W kolekcji mamy dwa modele Audi w które pytamy
            // Powinniśmy zobaczyć błąd:
            // Sequence contains more than one matching element
            var test2 = carList.Single(a => a.Model == "100");
            // W kolekcji nie mamy rekordu o CarId = 10
            // Powinniśmy zobaczyć błąd:
            // Sequence contains no matching element
            var test3 = carList.Single(a => a.CarId == 10);
            
        }
        private static void PrepareCollectionOfData()
        {
            carList = new List<Car>();
            carList.Add(new Car() { CarId = 1, Brand = "Audi", Model = "100" });
            carList.Add(new Car() { CarId = 2, Brand = "Audi", Model = "A1" });
            carList.Add(new Car() { CarId = 3, Brand = "Audi", Model = "A2" });
            carList.Add(new Car() { CarId = 4, Brand = "Audi", Model = "A3" });
            carList.Add(new Car() { CarId = 5, Brand = "Audi", Model = "A4" });
            carList.Add(new Car() { CarId = 6, Brand = "Audi", Model = "A5" });
            carList.Add(new Car() { CarId = 7, Brand = "Audi", Model = "100" });
            carList.Add(new Car() { CarId = 8, Brand = "Audi", Model = "A7" });
            carList.Add(new Car() { CarId = 9, Brand = "Audi", Model = "A8" });
        }
    }
    class Car
    {
        public int CarId { get; set; }
        public string Brand { get; set; }
        public string Model { get; set; }
        public string Date { get; set; }
    }
}