Deep Dive into LINQ シリーズ記事一覧
はじめに
この記事は Deep Dive into LINQ
シリーズの第1回目の記事です。
Deep Dive into LINQ
シリーズでは、 LINQ の内部実装やパフォーマンス特性について基本的なことから調べていきます。
まずは数回に分けて LINQ の First
メソッドについて研究していきます。
最初に First
メソッドを選んだのは、「初回」ということと、処理が比較的シンプルであるという理由からです。
今回は基本的な実装例を見ながら、 First
メソッドと FirstOrDefault
メソッドの使い方を見ていきます。
First
メソッド
First
メソッドとは、シーケンスの最初の要素を取得するメソッドです。
類似のメソッドとして、 FirstOrDefault
メソッドもあります。
First
メソッドは最も基本的な LINQ のメソッドの一つです。
条件なし First
メソッド
最も単純な First
メソッドの定義は以下のようになります。
public static TSource First<TSource>(this IEnumerable<TSource> source)
このメソッドはシーケンスの最初の要素を返します。もし最初の要素がない場合(すなわち、シーケンスが空っぽの場合)は InvalidOperationException
が発生します。
string[] array = new[] { "first", "second", "third" };
// 最初の要素 "first" が返る
var first = array.First();
Assert.Equal("first", first);
// 要素が一つもない場合は InvalidOperationException が発生する
string[] emptyArray = Array.Empty<string>();
Assert.Throws<InvalidOperationException>(() =>
{
_ = emptyArray.First();
});
条件付き First
メソッド
また、「条件」を受け取るオーバーロードもあります。
public static TSource First<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
このメソッドは与えられた条件を満たす最初の要素を返します。
どの要素も条件を満たさない場合は InvalidOperationException
が発生します。
int[] array = new[] { 1, 2, 3, 4, 5 };
// 最初の偶数 (2) を取得
var firstEven = array.First(x => x % 2 == 0);
Assert.Equal(2, firstEven);
// 条件に一致する要素がなければ InvalidOperationException が発生する
Assert.Throws<InvalidOperationException>(() =>
{
// 10 より大きい要素は存在しない
_ = array.First(x => x > 10);
});
条件なし FirstOrDefault
メソッド
FirstOrDefault
メソッドの定義は下記のようになっています。
public static TSource? FirstOrDefault<TSource>(this IEnumerable<TSource> source)
First
メソッドとほとんど同じですが、 FirstOrDefault
メソッドは空のシーケンスの場合に例外を発生させる代わりにデフォルト値を返します。
int[] array = new[] { 1, 2, 3, 4, 5 };
// 最初の要素 (1) が返る
var first = array.FirstOrDefault();
Assert.Equal(1, first);
int[] emptyArray = Array.Empty<int>();
// 空の配列に対してはデフォルト値 (0) が返る
var firstOfEmptyArray = emptyArray.FirstOrDefault();
Assert.Equal(0, firstOfEmptyArray);
// デフォルト値は指定することもできる
var firstOfEmptyArray2 = emptyArray.FirstOrDefault(100);
Assert.Equal(100, firstOfEmptyArray2);
また、シーケンスが空っぽの場合のデフォルト値を指定することもできます。 その場合は下記のメソッドが使われます。
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, TSource defaultValue)
条件付き FirstOrDefault
メソッド
FirstOrDefault
にも条件を受け取るメソッドがあります。
public static TSource? FirstOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
条件なしの場合と同様に、デフォルト値を指定することもできます。
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate, TSource defaultValue)
条件を満たす最初の要素を返し、条件を満たす要素が一つもなければデフォルト値を返します。
int[] array = new[] { 1, 2, 3, 4, 5 };
// 最初の偶数 (2) を取得
var firstEven = array.FirstOrDefault(x => x % 2 == 0);
Assert.Equal(2, firstEven);
// 条件に一致する要素がなければデフォルト値を返す
// 10 より大きい要素は存在しないので 0 が返る
var greaterThan10 = array.FirstOrDefault(x => x > 10);
Assert.Equal(0, greaterThan10);
// デフォルト値を指定することもできる
var greaterThan10Or999 = array.FirstOrDefault(x => x > 10, 999);
Assert.Equal(999, greaterThan10Or999);
まとめ
今回は First
と FirstOrDefault
について、基本的な挙動や使い方を見てきました。
どちらも「最初の要素を返す」メソッドですが、要素がなかった場合の挙動について、
First
メソッド: 例外 (InvalidOperationException
) を投げるFirstOrDefault
メソッド: デフォルト値を返す(例外は発生しない)
という違いがあります。
次回からは First
メソッドの内部実装やパフォーマンス特性などを調べていきます。