First vs FirstOrDefault vs Single vs SingleOrDefault in C

In C# LINQ, retrieving a specific element from an IEnumerable<T> collection is a common task, usually accomplished using First, FirstOrDefault, Single, or SingleOrDefault. While all four methods return a single item from a sequence, they differ significantly in how they handle collections with zero elements or more than one matching element. Choosing the right method depends on whether missing items or duplicate entries are expected or should be treated as application-breaking errors.

Quick Behavior Comparison

Method Behavior on Empty Sequence Behavior on Exactly One Match Behavior on Multiple Matches
First() Throws InvalidOperationException Returns the item Returns the first item
FirstOrDefault() Returns default(T) Returns the item Returns the first item
Single() Throws InvalidOperationException Returns the item Throws InvalidOperationException
SingleOrDefault() Returns default(T) Returns the item Throws InvalidOperationException

1. First()

First() retrieves the first element in a collection or the first element that satisfies a specified predicate.

  • Success: Returns the very first matching element and stops evaluating the rest of the sequence.
  • Empty Sequence: Throws an InvalidOperationException ("Sequence contains no elements").
  • Multiple Matches: Does not care; it takes the first match and ignores any subsequent items.

When to use: Use First() when you are certain at least one matching element exists and having multiple matches is acceptable or expected.


2. FirstOrDefault()

FirstOrDefault() behaves like First(), but instead of throwing an exception when no matching element is found, it returns the default value for the type (null for reference types, 0 for numeric types, false for booleans, etc.). You can also specify an explicit default value in modern .NET versions.

  • Success: Returns the first matching element.
  • Empty Sequence: Returns default(T) (or a user-specified fallback value).
  • Multiple Matches: Returns the first matching item without checking the remaining elements.

When to use: Use FirstOrDefault() when an element might not exist, and your code can gracefully handle a null or default value.


3. Single()

Single() asserts that there is exactly one element in the sequence matching the condition.

  • Success: Returns the sole matching element.
  • Empty Sequence: Throws an InvalidOperationException ("Sequence contains no elements").
  • Multiple Matches: Throws an InvalidOperationException ("Sequence contains more than one matching element").

Because it must ensure no second element exists, Single() may iterate through the entire sequence even after finding the first match.

When to use: Use Single() when business logic dictates that having zero or multiple records represents an invalid state (e.g., querying an entity by a unique primary key where the record must exist).


4. SingleOrDefault()

SingleOrDefault() allows for zero or one element.

  • Success: Returns the matching element if exactly one exists.
  • Empty Sequence: Returns default(T).
  • Multiple Matches: Throws an InvalidOperationException ("Sequence contains more than one matching element").

Like Single(), it scans further in the collection to verify that a duplicate does not exist.

When to use: Use SingleOrDefault() when a match is optional, but having more than one match indicates corrupt data or an unexpected state (e.g., looking up a user by a unique email address).


Summary of Best Practices

  • Choose First / FirstOrDefault when multiple matches are acceptable or when performance is critical on large datasets, as they can stop iterating as soon as the first match is found.
  • Choose Single / SingleOrDefault when uniqueness is mandatory. They carry a minor performance cost because they continue enumerating to guarantee that no second match exists, but they provide built-in validation against duplicate data.