C# LINQ First: Syntax, Behavior, and Pitfalls
c# linq first: Learn how to use LINQ First in C# to retrieve the first element of a sequence, handle exceptions, and choose between First and FirstOrDefault.
c# linq first requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
The First method in LINQ retrieves the first element from a sequence. It is one of the most commonly used sequence operators, but its behavior when the sequence is empty often surprises developers. This article explains the syntax, runtime behavior, and practical considerations for using First in C#.
How First Works on Sequences
First is an extension method defined in System.Linq.Enumerable for IEnumerable<T>. It returns the first element of the sequence. If the sequence contains no elements, it throws an InvalidOperationException. The method has two overloads: one without a predicate and one with a predicate that filters the sequence before selecting the first match.
var numbers = new List<int> { 10, 20, 30 }; int first = numbers.First(); Console.WriteLine(first); // 10
The method enumerates the sequence and returns the first element it encounters. For a collection that implements IList<T>, the implementation can directly index into the collection, avoiding a full enumeration. For other IEnumerable<T> sources, it uses the enumerator and moves to the first element.
First vs FirstOrDefault
The most common alternative to First is FirstOrDefault. The difference is in the empty-sequence case: FirstOrDefault returns the default value of the type (null for reference types, zero for numeric types) instead of throwing. This makes it suitable when the absence of an element is a valid condition rather than an error.
var empty = new List<string>(); string value = empty.FirstOrDefault(); Console.WriteLine(value == null); // True
Choosing between them depends on whether an empty sequence represents a failure. If the sequence must contain at least one element, First will surface that expectation immediately. If the caller can handle an empty result, FirstOrDefault avoids exception overhead and keeps control flow explicit.
Using First with a Predicate
The predicate overload lets you find the first element that satisfies a condition. It throws InvalidOperationException if no matching element exists, just like the parameterless version.
var orders = new List<Order> { /* ... */ }; Order urgent = orders.First(o => o.Priority == Priority.High);
This overload is useful when you know a matching element must exist. If the condition can legitimately match zero elements, use FirstOrDefault with the same predicate.
Common Exceptions and How to Avoid Them
The primary exception is InvalidOperationException, thrown when the sequence is empty or no element matches the predicate. This exception is a clear signal that the caller's assumption about the data is wrong. To avoid it, you can check the sequence length first, but that often adds an extra enumeration. A more idiomatic approach is to use FirstOrDefault and then check for the default value.
var item = items.FirstOrDefault(i => i.Id == requestedId); if (item == null) { // handle missing item }
For value types, you may need to use a nullable type or a sentinel value to distinguish "no result" from a valid default.
Performance and Lazy Evaluation
First does not force the entire sequence to be enumerated. It stops after the first matching element is found. For a sequence backed by a database query (e.g., Entity Framework), this translates to a query that returns a single row, which is efficient. However, if the source is an IEnumerable<T> that performs expensive computation per element, the cost is limited to the elements examined before the first match.
For collections that implement IList<T>, First uses direct indexing, so it runs in O(1) time. For other sequences, it calls MoveNext once, which is still O(1) for most practical sources. The overhead is minimal, but the exception path in First is more expensive than a null check, so FirstOrDefault is preferred in performance-sensitive code where an empty result is common.
Matching First, Single, and Take(1)
First should not be confused with Single, which also returns the first element but throws if the sequence contains more than one match. Use Single when the sequence must have exactly one element; use First when you only care about the first element regardless of additional ones. Take(1) returns a sequence of one element, which is useful when you want to chain further LINQ operations without triggering an exception.
| Method | Empty sequence behavior | Multiple elements behavior |
|---|---|---|
| First | Throws | Returns first |
| FirstOrDefault | Returns default | Returns first |
| Single | Throws | Throws |
| Take(1) | Returns empty sequence | Returns sequence with first item |
The choice depends on the invariant you want to enforce. If the data model guarantees uniqueness, Single is more defensive. If you only need the first record, First is appropriate.
Maintainability and Readability Considerations
Using First in code communicates that the sequence is expected to be non-empty. This is a form of documentation. However, it also couples the method to the data's state. In a codebase where empty sequences are common, FirstOrDefault with an explicit null check often reads better because it makes the fallback behavior visible.
When you do use First, consider whether the exception message is sufficient for debugging. You can wrap the call in a helper method that provides context:
public static T FirstOrThrow<T>(this IEnumerable<T> source, string message) { return source.FirstOrDefault() ?? throw new InvalidOperationException(message); }
This keeps the intent clear and avoids repeating the same exception handling logic.