Language Integrated Query (LINQ) 是 Visual Studio 2008 與 .NET Framework 3.5 引入的里程碑式創新,它在物件世界與資料世界之間架起了強型別、編譯時期可驗證的橋樑。傳統上,查詢以字串形式表達 (如 SQL、XPath),缺乏 IntelliSense 與型別安全;LINQ 將查詢提升為 C# / VB 的第一級語言建構,讓開發者能用熟悉的關鍵字與運算子對強型別集合進行查詢。
實作 IEnumerable<T> 介面的物件皆可作為 LINQ 資料來源:陣列 (T[])、List<T>、自訂集合、ADO.NET DataTable、XML 文件 (XElement) 等。資料來源決定了查詢的執行引擎:LINQ to Objects、LINQ to SQL、LINQ to XML、LINQ to Entities 等。
查詢定義「要取什麼資料」以及「如何篩選、排序、分組、投影」。關鍵特性:**查詢變數本身不執行任何操作,也不回傳資料,它只是儲存查詢定義**。
// 查詢變數 numbersQuery 僅保存定義,尚未執行
var numbersQuery = from n in numbers
where n % 2 == 0
select n;
查詢定義後不立即執行,而是在後續枚舉時 (如 foreach) 才真正逐筆產生結果。這帶來組合性優勢:可在執行前進一步修飾查詢 (加 Take、OrderBy 等)。
foreach (var n in numbersQuery) // 此處才真正執行查詢
Console.WriteLine(n);
套用會產生單一值的標準查詢運算子時,查詢會立即執行並回傳具體結果:
Count()、Max()、Average()、Sum()First()、Single()、ElementAt()ToList()、ToArray()、ToDictionary()// 立即執行並回傳 List<int>
var evensList = (from n in numbers where n % 2 == 0 select n).ToList();
// 立即執行並回傳偶數個數
int evenCount = (from n in numbers where n % 2 == 0 select n).Count();
C# 提供兩種等價語法:
from x in src where ... select ...,編譯器會轉換為方法呼叫。src.Where(...).Select(...)**,適用於不支援查詢語法的運算子 (如 Count、Skip)。兩者可自由混用,建議以可讀性為優先考量。
| 分類 | 代表運算子 | 執行模式 |
|---|---|---|
| 篩選 | Where, OfType | 延遲 |
| 排序 | OrderBy, ThenBy, Reverse | 延遲 |
| 分組 | GroupBy, ToLookup | 延遲 |
| 投影 | Select, SelectMany | 延遲 |
| 聯結 | Join, GroupJoin | 延遲 |
| 集合 | Distinct, Union, Intersect, Except | 延遲 |
| 分頁 | Take, Skip, TakeWhile, SkipWhile | 延遲 |
| 量詞 | Any, All, Contains | 立即 |
| 聚合 | Count, Sum, Min, Max, Average, Aggregate | 立即 |
| 元素 | First, Last, Single, ElementAt, DefaultIfEmpty | 立即 |
| 轉換 | ToList, ToArray, ToDictionary, AsEnumerable | 立即 |
foreach 或 ToList() 會重複查詢資料來源。解法:以 ToList() 具體化後重用。IQueryable,查詢會轉譯為 SQL 在資料庫端執行;若過早呼叫 AsEnumerable() 或在記憶體中操作,會導致全表掃描。Select、Where 可能拋出 NullReferenceException。善用 ?. 或 DefaultIfEmpty() 防禦。掌握 LINQ 查詢的三階段生命週期、延遲與立即執行的區別、標準查詢運算子分類與執行語意,是寫出高效、可維護資料存取程式碼的基石。善用 LINQ 強型別優勢,將業務邏輯以宣告式方式表達,能顯著降低「字串 SQL」帶來的維護成本與執行風險。