CodeGym /課程 /C# SELF /LINQ 語法:Method Syntax vs Query Syntax

LINQ 語法:Method Syntax vs Query Syntax

C# SELF
等級 31 , 課堂 1
開放

1. 前言

在 LINQ 的世界裡有兩大「流派」寫查詢,兩種語法風格,乍看之下好像完全不一樣。就是 Query Syntax(查詢語法)跟 Method Syntax(方法語法)。如果你以為寫程式就是很邏輯的事,今天我們要加點藝術感,因為選語法就像選畫筆還是鉛筆:兩個都能畫圖,但一個比較適合上色,一個比較適合勾線。

為什麼要有兩種語法?這問題問得好!想像你要點咖啡。你可以說:「可以來一杯加牛奶和一匙糖的濃縮咖啡嗎?」,也可以寫在紙上:「濃縮。牛奶。1 糖」。兩種都懂,但一個比較口語,一個比較精簡。

LINQ 也是這樣。一種語法設計得很像資料庫語言 SQL,另一種則更「C# 風」也更彈性。最後 C# 編譯器都會把這兩種語法轉成一樣的東西:方法呼叫。所以選哪種,通常就是看你覺得哪個好讀、自己喜歡哪個。

我們來看看兩種寫法。

2. Method Syntax

這種寫法就是一直用點(.)串接 LINQ 的 extension methods。這種方式在 .NET 開發者裡超紅,因為很容易加新操作,結果永遠是 IEnumerable<T>,而且直接寫在程式裡很順手。

範例:篩選並排序商品


var filteredProducts = products
    .Where(p => p.Price < 1000)          // 依價格篩選
    .OrderBy(p => p.Name)                // 依名稱排序
    .ToList();                           // 轉成 List<Product>

WhereOrderByToList 都是 LINQ 的 extension methods,每個都會回傳一個新的資料集,可以繼續處理下去。

流程圖


graph LR
A[products] --> B[Where]
B --> C[OrderBy]
C --> D[ToList]
Method Syntax 的呼叫順序

Method Syntax 的優點

  • 超彈性:可以很輕鬆串很多操作。
  • 全部都是 C# 方法,IDE 會自動補齊。
  • LINQ 幾乎所有功能都能用(甚至更多)。

再一個例子:選出所有 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 風語法)

這種語法就是為了讓 C# 開發者有 SQL 的熟悉感。它長得很像資料庫查詢,開頭是 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 的查詢步驟

Query Syntax 的優點

  • 很像 SQL,對有資料庫經驗的人超直覺。
  • 查詢很長、有多個條件、分組、join 時更好讀(join)。

再一個例子:選出成年用戶的名字


var adultNames = 
    from u in users
    where u.Age >= 18
    select u.Name;

注意:這裡 select 後面可以直接選欄位,不一定要整個物件,比如只要名字。

4. 比較:Method Syntax vs Query Syntax

Method Syntax Query Syntax
語法
users.Where(...).Select(...)
from u in users where ... select ...
像什麼 一般方法/串接 SQL
適用場合 任何操作都能用 不是所有操作都能用(像
Sum
Count
只能用 Method Syntax)
可讀性 串接時很好讀 分組、join 時更好讀
回傳什麼 通常是
IEnumerable<T>
通常是
IEnumerable<T>
,但有時要
.ToList()
才會變成清單

真實世界小知識

微軟官方 LINQ 文件的範例通常兩種寫法都給。但實務上 Method Syntax 越來越常見,因為跟 extension methods(WhereSelectOrderBy 等等)搭配起來超順。

要不要混著用?怎麼選風格

可以在同一個專案(甚至同一個查詢)混用兩種語法(但這樣看起來怪怪的)。重點是不要讓程式碼變成大雜燴。通常一個模組或專案選一種風格,大家比較好讀。

Method Syntax 很適合連續轉換、用到所有 LINQ 方法(像 SumCountAny 等只有方法版的)。

Query Syntax 超適合 joingroup by 或多層條件的情境——這時候可讀性大勝。

5. 風格轉換:同一件事不同寫法

C# 裡的 LINQ 會把你寫的 SQL 風查詢(Query Syntax)轉成方法串接(Method Syntax)。也就是說,不管你怎麼寫,C# 編譯時都會變成 extension methods。

範例 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(joingroup 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(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. 常見錯誤、陷阱和小技巧

最常見的誤會之一:如果你沒加 .ToList(),結果不是清單,而是「延遲查詢」(lazy query),只有第一次迭代時才會執行。這很方便,但如果原本的集合在查詢後有變動,可能會出現意料外的結果。延遲執行的細節我們之後會再聊(等你熟 LINQ 方法後)。

很多新手會搞混,不是所有 LINQ 方法都能用在 Query Syntax。例如不能直接寫 select sum(u.Age),要改用 Method Syntax(users.Sum(u => u.Age))。

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION