LINQの読み方は「リンク」|C#・.NETの統合言語クエリを基礎から解説
LINQの読み方は「リンク」です。Language Integrated Query(統合言語クエリ)の頭文字をとった名前で、C#や.NETでコレクション・データベース・XMLなどを同じ書き方で検索・加工できる機能を指します。この記事では、読み方と意味から、クエリ構文とメソッド構文の使い分け、よく使うメソッド、つまずきやすい遅延実行の挙動、そしてJavaやVB.NETでの相当機能までを一度に整理します。C#を触り始めた人が「LINQとは何で、どう書き、どこに注意するか」を最短で押さえられる構成にしました。
まとめ:この記事の要点
- 読み方は「リンク」。正式名称は Language Integrated Query(統合言語クエリ)。
- C# 3.0/.NET Framework 3.5(Visual Studio 2008、2007年)で導入された言語機能。
- 書き方はクエリ構文(SQLライク)とメソッド構文(ラムダ式のメソッドチェーン)の2種類。現在はメソッド構文が主流。
- LINQは定義した時点では実行されない遅延実行。同じクエリを何度も回すと再評価が走るため、確定時は
ToList()で1回に固定する。 - 対象別に LINQ to Objects/LINQ to Entities(EF Core)/LINQ to XML があり、旧来の LINQ to SQL は EF Core が後継。
- Javaに同名機能はなく Stream API が相当、VB.NETはLINQ対応。高速化が要る場面ではZLinqなどの選択肢がある。
LINQの読み方・意味と登場の経緯
LINQは「リンク」と読みます。ハイパーリンクの「リンク(link)」と同じ音のため紛らわしいですが、綴りは LINQ=Language INtegrated Queryで、日本語では「統合言語クエリ」または「言語統合クエリ」と訳されます。「lin-q」「リンキュー」と表記されることもありますが、Microsoftの読みは一貫して「リンク」です。
登場は2007年、C# 3.0と.NET Framework 3.5、Visual Studio 2008でのことです。C#の設計者アンダース・ヘルスバーグらのチームが、データベースはSQL、コレクションはforeach、XMLはXPath……とデータソースごとにバラバラだった問い合わせ方法を、言語の中に組み込んだ統一構文へまとめたのがLINQです。「クエリ(問い合わせ)をC#の文法として書ける」点がSQLとの決定的な違いで、変数名やプロパティ名の誤りをコンパイル時に検出できます。
LINQの書き方:クエリ構文とメソッド構文
LINQには2つの記法があります。どちらも同じ結果になり、内部的にはクエリ構文がメソッド構文へ変換されて実行されます。
クエリ構文(SQLに近い書き方)
from … where … orderby … select とSQLに似た並びで書く方式です。SQL経験者には読みやすく、複数ソースの結合(join)や複雑なグループ化では見通しが良くなります。
var result = from item in items
where item.Price >= 1000
orderby item.Price descending
select item;
メソッド構文(ラムダ式のメソッドチェーン)
Where や OrderByDescending などの拡張メソッドを . でつなぎ、条件をラムダ式で渡す方式です。すべてのLINQ機能を呼び出せるのはこちらで、C#の現場ではメソッド構文が標準です。
var result = items
.Where(item => item.Price >= 1000)
.OrderByDescending(item => item.Price);
クエリ構文とメソッド構文の使い分け基準
基本はメソッド構文に統一し、複数テーブルの join や let を伴う複雑なクエリだけクエリ構文に切り替えると読みやすくなります。クエリ構文には Skip/Take/Count など一部のメソッドに対応する文法が無いため、結局メソッド呼び出しを混ぜることになり、記法を1本化した方が保守しやすいからです。ラムダ式そのものの書き方はJavaラムダ式の使いどころで解説した考え方と共通で、引数からデリゲート(関数)を短く書く仕組みです。
代表的なLINQメソッド一覧
実務で頻出のメソッドを役割別にまとめます。いずれも IEnumerable を返す(遅延実行される)ものと、ToList() や Count() のように即時に値を確定するものがあります。
| 分類 | メソッド | 役割 |
|---|---|---|
| 絞り込み | Where | 条件に合う要素だけ残す |
| 射影 | Select / SelectMany | 要素を変換/入れ子を平坦化 |
| 並び替え | OrderBy / ThenBy | 昇順・降順・第2キー |
| グループ化 | GroupBy | キー単位でまとめる |
| 結合 | Join / GroupJoin | 2つのソースを突き合わせる |
| 取得 | First / FirstOrDefault / Single | 先頭・唯一の要素を取り出す |
| 判定 | Any / All / Contains | 条件の存在・全一致を真偽で返す |
| 集計 | Count / Sum / Average / Aggregate | 件数・合計・平均・任意集計 |
| 範囲・重複 | Distinct / Skip / Take | 重複排除・ページング |
| 確定 | ToList / ToArray / ToDictionary | 遅延実行を打ち切り実体化 |
例えば「価格1000円以上の商品を高い順に、名前と価格だけ取り出す」処理は次のように1本で書けます。
var view = items
.Where(i => i.Price >= 1000)
.OrderByDescending(i => i.Price)
.Select(i => new { i.Name, i.Price });
.NET 9(C# 13、2024年)では CountBy・AggregateBy・Index が追加され、これまで GroupBy と Select を組み合わせていた「キー別の件数集計」を1メソッドで書けるようになりました。新メソッドの背景はC# 13とF# 9の新機能解説にまとめています。
遅延実行(Deferred Execution)と多重列挙の落とし穴
LINQで最も誤解されやすいのが実行タイミングです。Where や Select を書いた行ではクエリはまだ実行されません。実際にforeachで回したり ToList() を呼んだ瞬間に初めて評価されます。これを遅延実行と呼びます。
var query = items.Where(i => i.Price >= 1000); // ここでは未実行
var list = query.ToList(); // ここで初めて評価される
便利な一方で、同じクエリ変数を複数回列挙するとそのたびに元データを走査し直すのが罠です。query.Count() の後に foreach (var x in query) と続ければ、2回スキャンが走ります。データベース相手のLINQ(EF Core)なら、この多重列挙がSQLの再発行につながり、いわゆるN+1問題の温床になります。
結果を2回以上使うなら、最初に一度だけ ToList() で確定させるのが定石です。逆に、巨大なコレクションを1回しか使わない場合は ToList() で全件をメモリに載せる方が無駄になります。「使い回すなら確定、1回きりなら遅延のまま」が判断基準です。なお Select で毎回 new するようなホットパスでは割り当てコストが効いてくるため、値型を多用する処理やボックス化を避ける設計と併せて見直すと効果的です。Unityや大量データでアロケーションを削りたい場合は、ゼロアロケーション版のZLinqという選択肢もあります。
LINQの種類(プロバイダ):Objects・EF Core・XML
LINQは対象とするデータソースごとに「プロバイダ」が分かれています。書き方は共通でも、裏側の実行方法が異なります。
- LINQ to Objects:メモリ上のリストや配列(
IEnumerable)が対象。最も基本的で、本記事のコード例もこれにあたる。 - LINQ to Entities(Entity Framework、現行はEF Core):データベースが対象。
IQueryableを通じてLINQ式がSQLへ翻訳され、DB側で絞り込みが実行される。大量データはここでWhereを効かせるのが鉄則。 - LINQ to XML:XML文書が対象。
XDocument/XElementをLINQで検索・生成できる。
「LINQ to SQL」という名前を見かけますが、これは.NET Framework時代の初期プロバイダで、現在はEntity Framework(EF Core)が後継です。新規開発でSQL Serverなどのデータベースを扱うなら、LINQ to SQLではなくEF Coreを選びます。
他言語でのLINQ相当機能:Java・VB.NET
「Java LINQ」「VB.NET LINQ」で調べる人が多いので、他言語での立ち位置を整理します。
Javaに標準のLINQはありません。相当するのはJava 8で入ったStream APIで、list.stream().filter(...).map(...).collect(...) のようにLINQと同じ発想でコレクションを加工します。Whereに当たるのが filter、Selectが map、遅延実行の考え方も共通です。SQL寄りの型安全なクエリが欲しい場合はjOOQやjinqといったサードパーティ製ライブラリが選択肢になります。Stream APIとラムダ式の組み合わせ方はJavaラムダ式の使いどころで具体例を挙げています。
VB.NETはLINQに対応しています。C#と同じ.NET上で動くため機能は同等で、むしろクエリ構文はVBの方が表現が豊富です(Aggregate・Distinct・Skip While などがキーワードとして用意されている)。C#で書いたLINQの知識はそのままVB.NETでも通用します。
LINQを手軽に試すツール:LINQPad
LINQを学ぶときに便利なのがLINQPadです。Joseph Albahari氏が公開している軽量ツールで、Visual Studioのようにプロジェクトを作らなくても、LINQやC#のコード片をその場で実行して結果を確認できます。.Dump() を付けるだけで途中結果を表として可視化できるため、クエリの組み立てやメソッドの挙動確認に向きます。無償版でも基本機能は使え、LINQの試し書きには十分です。
よくある質問
LINQの読み方は何ですか?
「リンク」です。Language Integrated Query(統合言語クエリ)の略で、ハイパーリンクと同じ音ですが別の概念です。
LINQとSQLの違いは何ですか?
SQLはデータベース専用で、クエリを文字列として書くため誤りは実行時まで分かりません。LINQはC#の文法として書けるため、コンパイル時に型やプロパティ名のチェックが効き、リストやXMLなどデータベース以外も同じ構文で扱えます。
クエリ構文とメソッド構文はどちらを使うべきですか?
普段はメソッド構文に統一するのがおすすめです。すべてのLINQ機能を呼び出せるうえ記法が一貫します。複数ソースのjoinなど、SQLに近い形の方が読みやすい複雑なクエリだけクエリ構文を使うと良いでしょう。
JavaでLINQは使えますか?
Javaに同名の機能はありません。Java 8以降のStream APIがLINQ相当で、filter/map/collect などでコレクションを加工します。
LINQは遅いのですか?
使い方次第です。LINQは遅延実行のため、同じクエリを何度も列挙すると走査が繰り返されます。結果を使い回すなら ToList() で一度確定させ、データベースでは絞り込みをDB側(EF CoreのIQueryable)で効かせれば、実用上問題になりません。