Deep Dive into LINQ Series:
Introduction
This article is the first in the Deep Dive into LINQ
series.
In the Deep Dive into LINQ
series, we will examine the basics of LINQ's internal implementation and performance characteristics.
First, we will study the First
method of LINQ in several parts.
We chose the First
method first because it is the "first time" and the process is relatively simple.
First
Method
The First
method is a method that retrieves the first element of a sequence.
A similar method is the FirstOrDefault
method.
The First
method is one of the most basic LINQ methods.
Conditionless First
method
The simplest First
method definition is as follows:
public static TSource First<TSource>(this IEnumerable<TSource> source)
This method returns the first element of the sequence.
If the first element is missing (i.e., the sequence is empty), an InvalidOperationException
is thrown.
string[] array = new[] { "first", "second", "third" };
// first element "first" is returned
var first = array.First();
Assert.Equal("first", first);
// InvalidOperationException is thrown if none of the elements are present
string[] emptyArray = Array.Empty<string>();
Assert.Throws<InvalidOperationException>(() =>
{
_ = emptyArray.First();
});
Conditional First
method
There are also overloads that receive predicates.
public static TSource First<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
This method returns the first element that satisfies the given conditions.
If none of the elements satisfy the condition, an InvalidOperationException
is thrown.
int[] array = new[] { 1, 2, 3, 4, 5 };
// Get the first even number (2)
var firstEven = array.First(x => x % 2 == 0);
Assert.Equal(2, firstEven);
// InvalidOperationException is thrown if no elements match the condition
Assert.Throws<InvalidOperationException>(() =>
{
// No element greater than 10 exists.
_ = array.First(x => x > 10);
});
FirstOrDefault
method without condition
The definition of the FirstOrDefault
method is as follows.
public static TSource? FirstOrDefault<TSource>(this IEnumerable<TSource> source)
Almost identical to the First
method, but the FirstOrDefault
method returns a default value instead of throwing an exception for an empty sequence.
int[] array = new[] { 1, 2, 3, 4, 5 };
// first element (1) is returned
var first = array.FirstOrDefault();
Assert.Equal(1, first);
int[] emptyArray = Array.Empty<int>();
// default value (0) is returned for an empty array
var firstOfEmptyArray = emptyArray.FirstOrDefault();
Assert.Equal(0, firstOfEmptyArray);
// Default value can also be specified
var firstOfEmptyArray2 = emptyArray.FirstOrDefault(100);
Assert.Equal(100, firstOfEmptyArray2);
You can also specify a default value if the sequence is empty. In that case, the following method is used:
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, TSource defaultValue)
Conditional FirstOrDefault
method
FirstOrDefault
also has a method that takes a condition.
public static TSource? FirstOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
As with the no condition case, a default value can also be specified.
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate, TSource defaultValue)
This method returns the first element that satisfies the condition, or the default value if none of the elements satisfy the condition.
int[] array = new[] { 1, 2, 3, 4, 5 };
// Get the first even number (2)
var firstEven = array.FirstOrDefault(x => x % 2 == 0);
Assert.Equal(2, firstEven);
// If no element matches the condition, return the default value.
// 0 is returned because there is no element greater than 10.
var greaterThan10 = array.FirstOrDefault(x => x > 10);
Assert.Equal(0, greaterThan10);
// default values can also be specified
var greaterThan10Or999 = array.FirstOrDefault(x => x > 10, 999);
Assert.Equal(999, greaterThan10Or999);
Summary
In this article, we have looked at the basic behavior and usage of First
and FirstOrDefault
.
Both methods "return the first element", but they behave differently when there is no element:
First
method: throws an exception (InvalidOperationException
)FirstOrDefault
method: returns default value (no exception is thrown)
In the next and subsequent articles, we will examine in detail the internal implementation and performance characteristics of the First
method.