LINQについて勉強してみる

はいどーもお正月ですねこんにちは。
本日はC#のLINQについて勉強したいと思いますよ。

LINQを使うと何が嬉しいのか

LINQとは一体なんぞ? という話も大事と言えば大事だと思うのですが、僕としては「LINQを使うと一体なにが嬉しくなるのか? 便利なのか?」ということの方に興味があります。
というわけでまずは「何が便利になるのか」を調べてみました。

この記事によると、LINQのメリットは以下の通りです。

・少ない行数、ネスト数で簡潔なコードが書ける
・意図が伝わるがコードが書ける
・メソッドチェーンによる処理の組み合わせができる

上の2つはまあ見たまんまなので、三番目について少し詳しく見てみましょう。

メソッドチェーンによる処理の組み合わせができる理由

例えば以下のようなコードがあったとします。

Whereメソッドの終わりにSelectメソッドを繋げ、Selectメソッドの終わりにOrderByDescendingメソッドを繋げていますよね。
これがメソッドチェーンです。

なぜこのようなことができるのでしょうか?
それは、WhereメソッドもSelectメソッドもOrderByDescendingメソッドもIEnumerable<T>型を戻り値として返すからです。
そして、LINQのクエリ演算子(上述のメソッドのこと)はIEnumerable<T>型の拡張メソッドとして定義されています。

注*OrderByDescendingメソッドはIOrderedEnumerable型を返しますが、この型はIEnumerable<T>インターフェイスを含んでいます。

つまりどういうことだってばよ?

LINQのクエリ演算子はIEnumerable<T>型に対する拡張メソッドとして定義されていると書きました。
つまりクエリ演算子がIEnumerable<T>型を返す限り、その戻り値に対して再びクエリ演算子を用いることができるのです。
これがLINQのミソ(メソッドチェーンによる処理の組み合わせができる)の一つですね。

また、IEnumerable<T>型の拡張メソッドを独自に実装し、IEnumerable<T>型を返すようにすれば、そのメソッドをLINQの中で使うことができます。
実際にやってみましょう。

IEnumerable< T>型に対する拡張メソッドを実装する

IEnumerable<T>型に対する拡張メソッドを実装したいと思います。
特に実用的なものが思い浮かばなかったので、ここでは引数で指定された要素を抜き出すメソッドを作ることにしてみましょう。

1.静的クラスIEnumerableExtensionsを作成する
2.IEnumerable< T>型に対する拡張メソッドElements(int first, int last)を作成する

まずはここまでやりましょう。
拡張メソッドは静的クラスの中に作成しなければならなかったことを覚えているでしょうか?
拡張メソッドについては別の記事でまとめていますので、もし忘れていた方がいたら参照してみてください。
というわけで以下のような感じになります。

ご覧の通り、IEnumerable< T>型を返していますね。
また、第一引数でIEnumerable<T>型に対して利用できることを宣言しています。
これでList<int>だろうがDictionary<string, string>だろうが、IEnumerable<T>インターフェイスを実装しているクラスに対してならElements<T>メソッドを利用できるようになりました。

ちなみに中身は、firstからlast番目の要素を抜き出してるだけです。
例えば配列の中身が[0, 1, 2, 3, 4, 5]で、firstに1、lastに4を指定したとき[1, 2, 3, 4]が返ってきます。

拡張メソッドを実際に使用してみる

例のごとくコンソールアプリのMainメソッド内に直接書いていきましょう。

実行結果はこんな感じになります。

では順番に見ていきましょう。
一行目のList作成はいいですね。

次の行でlistに対し、OrderByDescendingメソッドを実行(降順に並び替え)し、その並び替えたシーケンスに対して自作の拡張メソッドElementsを実行しています。
結果はqueryに代入されていますね。

さて次はquery2です。
今回はlistに対してElementsメソッドを呼び、その結果をWhereメソッドで絞り込んでいます(偶数のみ取得)。
そして最後に昇順に並び替え、結果をquery2に代入しています。

特に難しいことはないですが、注目してほしいのは「LINQが用意しているクエリ演算子と同じように自作のElements拡張メソッドが使用できている」ことです。
LINQのメリットとして挙げられていた「メソッドチェーンによる処理の組み合わせができる」というのは、こういう意味も含んでいるんですね。

おわりに

本記事とはあまり関係がないですが、コレクション関連の記事の最後に書いていた

・デリゲート(イベント)
・LINQ

の記事の作成が終わったことになります(まあLINQはJavaScriptのLINQについて昨年ちょこっと書いてましたが……。興味のある方はブログ内をLINQで検索してみてください)。

ラムダ式については、現在「デリゲートを受け取る引数に渡せる」程度の認識しかありません(実際は式木とかあって複雑そう)。
もう少し学習が進んだらラムダ式についてもウンヌンカンヌンと書こうかなあと思います。

ちゅーわけで正月のお勉強を終わります。
またよろしこ。

フォローする