撰寫 LINQ 語法有兩種方式,其一是前一篇所講的「查詢運算式」,因為貼近 SQL Script,且較易閱讀,因此大受歡迎,但實際上還有一種撰寫方式,就是「方法架構查詢」,也就是本篇的主角。
自學筆記這系列是我自己學習的一些心得分享,歡迎指教。這系列的分享,會以 C# + 我比較熟的 Net 3.5 環境為主。
另外本系列預計至少會切成【打地基】和【語法應用】兩大部分做分享。打地基的部分,講的是 LINQ 的組成元素,這部分幾乎和 LINQ 無關,反而是 C# 2.0、C# 3.0 的一堆語言特性,例如:型別推斷、擴充方法、泛型、委派等等,不過都會把分享的範圍限制在和 LINQ 應用有直接相關功能。
PS. LINQ 自學筆記幾乎所有範例,都可直接複製到 LINQPad 4 上執行(大多是用 Statements 和 Program 模式)。因為它輕巧好用,功能強大,寫範例很方便,請大家自行到以下網址下載最新的 LINQPad:http://www.LINQpad.net/。
在 LINQ 簡介文件中,大部分範例都是使用 C# 3.0 引進的宣告式查詢語法,以查詢運算式(Query Expressions)的形式撰寫。不過,.NET Common Language Runtime(CLR)本身並沒有查詢語法的概念。因此,在編譯期間,查詢運算式會轉譯為 CLR 可以了解的項目:即方法呼叫(Method calls)。這些被呼叫的方法稱為「標準查詢運算子」(Standard Query Operator),其名稱就像查詢運算式的 LINQ 關鍵字,為 Where、Select、GroupBy、Join、Max、Average 等等。
這種呼叫標準查詢運算子的 LINQ 語法,專有名詞叫做「方法架構查詢」(Method-Based Query)。
一般而言,因為查詢運算式通常比較簡單易懂,所以微軟官方是建議開發人員可以的話,盡量優先使用查詢語法,那為什麼還需了解方法架構查詢呢?
有兩個很重要的原因:
再回到第一段的說明,有講到一件很重要的事:NET Common Language Runtime(CLR)本身並沒有查詢語法的概念。因此,在編譯期間,查詢運算式會轉譯為 CLR 可以了解的項目:即方法呼叫(Method calls)。
也就是說,雖然我們寫的是「查詢運算式」,但編譯器還是會先轉成「方法架構查詢」形式,再進行編譯,所以我們是否有方法可以快速了解撰寫的查詢語法其對應之方法語法為何?
就我知道的方式,標準答案就是看 MSDN 文件,自己動腦想辦法對應;第二種方式:反組譯編譯完的組件;不過另外還有一種方式更簡便,就是利用 LINQPad 的 Lambda translations 來幫我分析:
不過用 LINQPad 分析有個必要條件:查詢的資料來源必須實做 IQueryable<T>。
換言之,若是平常 LINQ to Objects,我們的資料來源是 IEnumerable<T>,那就無法用 Lambda translations 功能了:
from n in new[] { "Tom", "Dick", "Harry" }
where n.Contains ("a")
select n
但是我們可以透過 AsQueryable() 方法把資料來源轉換一下,就可以囉:
from n in new[] { "Tom", "Dick", "Harry" }.AsQueryable()
where n.Contains ("a")
select n
/* Lambda translations 輸出:
System.String[]
.Where (n => n.Contains ("a"))
*/
最後,該怎麼選擇要撰寫查詢運算式還是方法架構查詢?我個人會喜歡寫方法架構查詢,但說實在的,查詢運算式真的比較容易懂,所以我覺得就看個人囉!但是因為前面有講過,方法架構查詢可以使用所有的「標準查詢運算子」,但是查詢運算式只能使用大部分的運算子,所以兩種撰寫方式大家還是都必須了解,至少文件要看的懂咩。