緣起
前一陣子參與的專案裡, 用了不少 LINQ 的語法, 但沒有時間細推其原埋.依 MSDN 的官方說法: LINQ 的語法共有 2 種: 一個是 Query Syntax, 一個是 Method Syntax. 本文將作淺顯的說明.
另外, 亦將介紹一個工具 LINQPad 的工具, 在您還不是很熟悉 Method Syntax 的時候, 可以協助將 Query Syntax 轉為對應的 Method Syntax.
完整程式範例, 筆者放在 GitHub, 請由此下載.
名詞定義
- Query Syntax: 係指採用類類 SQL 敍述的 LINQ 語法.
- Method Syntax: 係指採用 Fluent Interface (or Extension Method) + Lambda Expression 的 LINQ 語法.
- 對於 Fluent Interface 有興趣者, 可以參考 小朱 的 [.NET] Fluent Interface: 實作 Method Chaining 又不會有耦合性的作法
- 註: 該篇文章有其它人留言: "不錯的Pattern; 不過因為 C# 3 之後有了Extension Methods 就沒再使用此方式, 因為 Extension Methods 把定義 interface 的步驟都省了...雖然只能用在.Net.但在其他語言這是個好方法."
- 對於 Lambda Expression 有興趣者, 可以參考 小朱 的 [.NET] 由委派演進到 Lambda Expression
class Program
{
static void Main(string[] args)
{
int[] numbers = { 5, 10, 8, 3, 6, 12 };
//Query syntax:
IEnumerable<int> numQuery1 =
from num in numbers
where num % 2 == 0
orderby num
select num;
//Method syntax:
IEnumerable<int> numQuery2 = numbers.Where(num => num % 2 == 0).OrderBy(n => n);
foreach (int i in numQuery1)
{
Console.Write(i + " ");
}
Console.WriteLine(System.Environment.NewLine);
foreach (int i in numQuery2)
{
Console.Write(i + " ");
}
// Keep the console open in debug mode.
Console.WriteLine(System.Environment.NewLine);
Console.WriteLine("Press any key to exit");
Console.ReadKey();
/*
Output:
6 8 10 12
6 8 10 12
*/
}
}
各位應該有注意到這段 IEnumerable<int> numQuery2 = numbers.Where(num => num % 2 == 0).OrderBy(n => n); Where 之後, 又來一個 OrderBy; 其實只要去看一下 Enumerable 的源碼就可以了解.
Where 的回傳值是 IEnumerable<TSource>, 而 OrderBy 也是 Enumerable 裡的一個擴充方法 (擴充 IEnumerable<TSource>, 所以可以這樣一直 . 下去.
Where 的源碼:
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
if (source == null) throw Error.ArgumentNull("source");
if (predicate == null) throw Error.ArgumentNull("predicate");
if (source is Iterator<TSource>) return ((Iterator<TSource>)source).Where(predicate);
if (source is TSource[]) return new WhereArrayIterator<TSource>((TSource[])source, predicate);
if (source is List<TSource>) return new WhereListIterator<TSource>((List<TSource>)source, predicate);
return new WhereEnumerableIterator<TSource>(source, predicate);
}
OrderBy 的源碼:
public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) {
return new OrderedEnumerable<TSource, TKey>(source, keySelector, null, false);
}
LINQPad 的操作
那麼上述的 Query Syntax 如何轉換為 Method Syntax 呢? 請參考下圖
![]() |
| Convert Query Syntax to Method Syntax with LINQPad |
總結
LINQ 的語法共有 2 種: 一個是 Query Syntax, 一個是 Method Syntax; 對於初學者而言, Query Syntax 是比較容易入門的; 但若要使程式更精鍊, 則還是要學習 Method Syntax.至於如何將 Query Syntax 轉為對應的 Method Syntax, 則可以利用 LINQPad 這個工具.
補充 (2015.12.04)
1. 修正參考自 小朱 部落格的相關文件連結.
2. 補充以下語法, 以處理回傳多個欄位的狀況
//Query syntax:
var numQuery1 =
from num in numbers.AsQueryable()
where num % 2 == 1
orderby num
select new { Num1 = num, Num2 = num + 1 }
;
foreach (var x in numQuery1)
{
Console.WriteLine(x.Num1 + " " + x.Num2);
}
//Method syntax:
var numQuery2 =
numbers.Where(num => ((num % 2) == 1))
.OrderBy(num => num)
.Select(num => new { Num1 = num, Num2 = num + 1 } )
;
foreach (var x in numQuery2 )
{
Console.WriteLine(x.Num1 + " " + x.Num2);
}
/* Output
3 4
5 6
*/
string[] words = { "aPpLe", "BaNaNa", "ORaNGe" };
//編繹時, var 會被改成 IEnumerable<<>f__AnonymousType0> 資料型態
var newwords = words.Select((w) => new { Upper = w.ToUpper(), Lower = w.ToLower() });
foreach (var x in newwords)
{
Console.WriteLine(x.Upper + " : " + x.Lower);
}
/* Output
APPLE : apple
BANANA : banana
ORANGE : orange
*/
參考文件
- 小朱 的 [.NET] Fluent Interface: 實作 Method Chaining 又不會有耦合性的作法
- 對 Fluent Interface 有興趣者, 可以參考這篇
- 小朱 的 [.NET] 由委派演進到 Lambda Expression
- 對 Lambda Expression 有興趣者, 可以參考這篇
- Query Syntax and Method Syntax in LINQ (C#)
- MSDN 官方網站
- mrkt 的 LINQPad - 好用到爆炸、.NET開發人員必備的好用工具
- demo 的 LINQPad 有在用LINQ不可或缺的好工具
- demo 的 保護眼睛專欄-LINQ 超好工具 LINQPad 也要變黑色主題(Dark Template)
- LINQPad 下載

沒有留言:
張貼留言