##はじめに
LINQとは、「Language INtegrated Query」の略で、C#やVB.netで、SQLのようなクエリ構文を記述する事で、複雑なデータ操作を簡単に実現できる構文とライブラリのセットの事です。
個人的にはLINQがあるからC#以外の言語に移行できないと考えるほど便利な機能だと思います。
しかし今までのC#開発プロジェクトではLINQが浸透しておらず、すごく勿体ないと感じています。
今回は簡単な例を使用してLINQの便利な一面を紹介します。
##何が便利なのか?
実際に使用している例を見たほうが早いと思います。
パス「C:\temp」の子フォルダの中のファイルのうち、拡張子「txt」と「log」ものを全て列挙する
###LINQを使用しないパターン
//判別したい拡張子
var extensions = new[] { ".txt", ".log" };
var files = new List<string>();
//ディレクトリ取得
foreach (var directory in Directory.GetDirectories(@"C:\temp"))
{
//ディレクトリ内のファイルを取得
foreach (var file in Directory.GetFiles(directory))
{
//拡張子で判別してファイル名追加
if (extensions.Contains(Path.GetExtension(file)))
files.Add(file);
}
}
まず「C:\temp」直下のフォルダ群をforeachで列挙して、そのフォルダでGetFilesしたファイルをforeachで列挙。拡張子が関係ないものif文で弾く処理になります。
foreachが入れ子になっていて、インデントが深くなるところがコードを見にくくしています。
###LINQを使ったパターン
//判別したい拡張子
var extensions = new[] { ".txt", ".log" };
var files = Directory.EnumerateDirectories(@"C:\temp")
.SelectMany(d => Directory.EnumerateFiles(d))
.Where(f => extensions.Contains(Path.GetExtension(f)))
.ToArray();
EnumerateFiles(Linqが使えるディレクトリ取得関数)で「C:\temp」内のディレクトリを取得します。
SelectManyで入れ子になったディレクトリ内のファイルをEnumerateFilesで取得します。
Whereで拡張子を判別して、最後に配列化します。
foreachを使う例に比べると、かなりあっさりした感じの実装になります。行数で言えば2行になります。
####どこが便利なのか?
上記2パターンを比べてもピンとこない人がいると思います。
- インデントが深くなるくらい大したことはない
- コメントを入れるスペースがなくなった
- そもそもforeachの方が馴染みがあるから見やすい
今までにLINQの説明をして返ってきた内容です。
####インデントが深くなるくらい大したことはない
インデント・入れ子の構造・行数は少なければいいということは無いと思いますが、多すぎると途端に読みにくいコードになってしまいます。
上記例では簡潔な内容ですが、フォルダ名の判別やファイルの属性の判別を追加すると、foreachの例ではさらにインデントが深くなってしまいます。
LINQの例ではメソッドチェーンで構成されているため変更・追加に対して簡単に実装が可能で、基本的にはインデント・行数ともに変化はありません。
####コメントを入れるスペースがなくなった
これはその通りかもしれません。
しかし、LINQ では処理の内容ごとに決まったメソッドが用意されているので、書いたコードが何をやっているのかが明確になります。
そのため、foreachでは処理に目的性が少ないためコメントが必要でしたが、LINQではコードで目的が分かるためコメント量が少なくて済むという考えができるかもしれません。
####そもそもforeachの方が馴染みがあるから見やすい
この考えがあるとなかなか新しいことに挑戦できなくなってしまいます。
効率的な書き方や新機能などを取り入れて、良いコードとは何かということを考えながら開発をしていきたいです。
##便利に思えましたか?
LINQは最初の印象で敬遠される人が多く、とてもとっつきにくい印象のある機能かもしれません。
処理の考え方も従来のfor文で回して考えるのではなく、集合で捉えると分かりやすいかもしれません。
また、SQLが得意な人でもコードに落とす段階になるとSQL的な考えをせずにロジックで考えてしまったり、意識的に考えを変える必要があります。
一度でも使って覚えてしまえばコーディング効率は飛躍的に上がると思うので、まだ使ったことが無いという人は是非使ってみてください。
##LINQで使用できる演算子
- フィルタ Where
- 射影(別のクラスに入れ替えたりする) Select, SelectMany
- ソート OrderBy, OrderByDescending, ThenBy, ThenByDescending
- 結合 Join, GroupBy, GroupJoin, Concat, Union, Zip
- 集合演算 Intersect, Subtract, Exclude, Distinct
- 判定 Count, Any, All
- 切り出し First, FirstOrDefault, Last, LastOrDefault, Single, ElementAt, Take, Skip
- 固定化 ToList, ToDictionary
- 演算 Aggregate, Sum, Average, Max, Min
##説明が出来なかった内容
- リンクの歴史
- 遅延評価
- LINQに使われている機能
- 型推論」「匿名クラス」「ラムダ式」