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/FirstOrDefaultwhen 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/SingleOrDefaultwhen 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.