Using LINQ `First` Method

Deep Dive into LINQ #1

Posted on 2022-03-03
target: .NET 6

Deep Dive into LINQ Series:

Part 1 - Using LINQ `First` Method

Part 2 - Implementing LINQ's First Method

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.