1. はじめに
LINQの世界には、クエリを書くときの2つの「流派」があるんだ。最初は全然違うものに見えるかもしれないけど、それがQuery Syntax(クエリ構文)とMethod Syntax(メソッド構文)。もし「プログラミングってロジックだけでしょ?」って思ってたら、今日はちょっとアートも混ぜてみるよ。構文の選び方って、筆と鉛筆どっちで絵を描くか選ぶのに似てるんだ。どっちも絵は描けるけど、色を出すのが得意なのと、輪郭を描くのが得意なのがあるよね。
なんで2つの構文があるの?いい質問!コーヒーを注文したいときのことを想像してみて。「エスプレッソにミルクと砂糖1つ、お願いします」って言うこともできるし、紙に「エスプレッソ。ミルク。砂糖1」って書くこともできる。どっちも伝わるけど、1つは会話っぽくて、もう1つはすごく簡潔だよね。
LINQも同じ。1つの構文はSQLっぽくて、もう1つは「C#らしさ」と柔軟さを重視してる。結局C#のコンパイラはどっちも同じ、メソッド呼び出しに変換しちゃうから、選ぶ基準は読みやすさとか好みになることが多いんだ。
じゃあ、両方見てみよう。
2. Method Syntax
これはLINQの拡張メソッドをドットでつなげて書くスタイル。特に.NET開発者には人気で、新しい操作を追加しやすいし、結果はいつもIEnumerable<T>だし、コードの中でそのまま書きやすいんだ。
例:商品をフィルタしてソートする
var filteredProducts = products
.Where(p => p.Price < 1000) // 値段でフィルタ
.OrderBy(p => p.Name) // 名前でソート
.ToList(); // List<Product>に変換
Where、OrderBy、ToListは全部LINQの拡張メソッドで、それぞれ新しいデータセットを返して、さらに処理を続けられるよ。
図解
graph LR
A[products] --> B[Where]
B --> C[OrderBy]
C --> D[ToList]
Method Syntaxのいいところ
- めっちゃ柔軟:いろんな操作をチェーンで簡単に組み立てられる。
- 全部C#のメソッドだから、IDEの補完も効く。
- LINQでできることはほぼ全部できる(それ以上も)。
もう1つの例:18歳以上のユーザーの名前を選ぶ
例えば、Userクラスがあるとする:
public class User
{
public string Name { get; set; }
public int Age { get; set; }
}
じゃあ、大人ユーザーの名前を選んでみよう:
List<User> users = ... // どこかで宣言されてる
var adultNames = users
.Where(u => u.Age >= 18)
.Select(u => u.Name)
.ToList();
3. Query Syntax(SQLっぽい構文)
この構文は、SQLに慣れてるC#開発者が使いやすいように作られたんだ。データベースのクエリっぽくて、fromキーワードから始まるよ。
例:同じフィルタとソート
var filteredProducts =
from p in products
where p.Price < 1000
orderby p.Name
select p;
これはまさにクラシックなクエリっぽいよね:"productsコレクションからpを取って、p.Price < 1000のやつ、p.Nameでソートして、pを選ぶ"って感じ。
図解
flowchart TD
A[products] -->|from p in products| B[where p.Price < 1000]
B --> C[orderby p.Name]
C --> D[select p]
Query Syntaxのいいところ
- SQLっぽいから、DB経験者には分かりやすい。
- 条件が多い長いクエリや、グループ化・結合(join)があるときは読みやすい。
もう1つの例:大人ユーザーの名前を選ぶ
var adultNames =
from u in users
where u.Age >= 18
select u.Name;
ポイント:ここではselectの後で、オブジェクト全体じゃなくて特定のフィールド(例えば名前だけ)を選べるよ。
4. 比較:Method Syntax vs Query Syntax
| Method Syntax | Query Syntax | |
|---|---|---|
| 構文 | |
|
| 似ているもの | 普通のメソッド/チェーン | SQL |
| どこで使う? | いつでも、どんな操作でもOK | 全部の操作はできない(例えばやはMethod Syntaxだけ) |
| 読みやすさ | チェーンには向いてる | グループ化や結合には便利 |
| 返すもの | だいたい |
だいたいだけど、リストにしたいときはが必要なことも |
リアルな豆知識
Microsoftの公式LINQドキュメントの例は、たいてい両方のスタイルで載ってる。でも実際の現場コードだと、Method Syntaxのほうがよく使われてる。拡張メソッド(Where、Select、OrderByなど)と組み合わせやすいからね。
混ぜる?混ぜない?どっちを選ぶ?
どっちも同じプロジェクトで自由に使ってOK(同じクエリで混ぜるのはちょっと変だけど)。大事なのは、コードがごちゃごちゃにならないこと。普通は1つのモジュールやプロジェクトでスタイルを統一して、読みやすくするよ。
Method Syntaxは、連続した変換や、Sum、Count、Anyみたいなメソッド構文だけのLINQメソッドを使うときにピッタリ。
Query Syntaxは、joinやgroup by、複雑な多段条件があるときに読みやすくて便利だよ。
5. スタイル変換:同じことを違う書き方で
C#の中のLINQは、どんなSQLっぽいクエリ(Query Syntax)も、最終的にはメソッド呼び出し(Method Syntax)に変換しちゃう。つまり、何を書いても、C#はコンパイル時に拡張メソッドにしちゃうんだ。
例1 — フィルタ:
Query Syntax:
var adults = from u in users
where u.Age >= 18
select u;
Method Syntax(同じ意味):
var adults = users.Where(u => u.Age >= 18);
例2 — フィールドの選択(Select):
Query Syntax:
var names = from u in users
select u.Name;
Method Syntax:
var names = users.Select(u => u.Name);
7. グループ化と結合(join、group by)
新しいオブジェクトを作る
じゃあ、アプリでユーザーを年齢ごとにグループ化して表示する機能を追加してみよう。ここで構文の違いが特に分かりやすくなるよ。
Query Syntax(グループ化):
var usersByAge =
from u in users
group u by u.Age into ageGroup
select new { Age = ageGroup.Key, Users = ageGroup.ToList() };
ユーザーを年齢でグループ化してる(group u by u.Age)。intoの後にageGroupって変数が出てくるけど、これがグループそのものだよ。
Method Syntax(同じ意味):
var usersByAge = users
.GroupBy(u => u.Age)
.Select(ageGroup => new { Age = ageGroup.Key, Users = ageGroup.ToList() });
さらに複雑:結合(join)
例えば、注文リスト(orders)とユーザーリスト(users)があるとする。ユーザーの名前と注文の合計金額を取得したい場合。
Query Syntax:
var userOrders =
from user in users
join order in orders on user.Id equals order.UserId
select new { user.Name, order.Amount };
Method Syntax:
var userOrders = users.Join(
orders,
user => user.Id,
order => order.UserId,
(user, order) => new { user.Name, order.Amount }
);
8. よくあるミス・落とし穴・小技
よくある勘違いの1つ:.ToList()を付けないと、結果はリストじゃなくて「遅延クエリ」(lazy query)になる。つまり、最初にループするときに実行されるんだ。これは便利だけど、元のコレクションが後から変わると予想外の結果になることもある。LINQメソッドを学んだ後で「遅延実行」について詳しく話すね。
初心者がよく混乱するのは、Query Syntaxでは全部のLINQメソッドが使えるわけじゃないこと。例えば、select sum(u.Age)みたいには書けなくて、Method Syntax(users.Sum(u => u.Age))に切り替える必要があるよ。
GO TO FULL VERSION