Language Integrated Query (LINQ) 是 C# 3.0 引入的革命性特性,提供統一的資料查詢語法。本文涵蓋查詢語法、方法語法、核心運算子、延遲執行機制與實用範例。
var highBmiPeople = from person in people
where person.Bmi > 25
orderby person.Bmi descending
select new { person.Name, person.Bmi };
var highBmiPeople = people
.Where(p => p.Bmi > 25)
.OrderByDescending(p => p.Bmi)
.Select(p => new { p.Name, p.Bmi });
| 分類 | 運算子 | 說明 |
|---|---|---|
| 篩選 | Where |
依條件篩選 |
OfType<T> |
依型別篩選 | |
Take / Skip |
取得/略過前 N 筆 | |
Distinct |
移除重複 | |
| 排序 | OrderBy / OrderByDescending |
主要排序 |
ThenBy / ThenByDescending |
次要排序 | |
Reverse |
反轉順序 | |
GroupBy |
分組 | |
| 投影 | Select |
轉換形狀 |
SelectMany |
扁平化投影 | |
Zip |
兩序列合併 | |
Join / GroupJoin |
內部/群組聯結 | |
| 集合 | Union / Intersect / Except |
聯集/交集/差集 |
Concat |
串連序列 | |
DefaultIfEmpty |
空序列預設值 | |
All / Any / Contains |
量詞判斷 | |
| 聚合 | Count / Sum / Average / Min / Max |
基本聚合 |
Aggregate |
自訂累積 | |
GroupBy + 聚合 |
分組統計 |
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public double Bmi { get; set; }
public string Department { get; set; }
public List Skills { get; set; }
}
public class LinqDemo
{
private List _people = new()
{
new Person { Name = "Alice", Age = 28, Bmi = 22.5, Department = "IT", Skills = new() { "C#", "SQL" } },
new Person { Name = "Bob", Age = 35, Bmi = 27.3, Department = "HR", Skills = new() { "Recruiting" } },
new Person { Name = "Charlie", Age = 42, Bmi = 31.2, Department = "IT", Skills = new() { "C#", "Azure" } },
new Person { Name = "Diana", Age = 29, Bmi = 24.8, Department = "Finance", Skills = new() { "Excel", "C#" } },
};
public void RunExamples()
{
// 1. 篩選 + 投影:BMI > 25 的人名
var names = _people
.Where(p => p.Bmi > 25)
.Select(p => p.Name);
Console.WriteLine("高 BMI 人員:" + string.Join(", ", names));
// 2. 分組統計:各部門平均年齡
var deptAvgAge = _people
.GroupBy(p => p.Department)
.Select(g => new { Department = g.Key, AvgAge = g.Average(p => p.Age) });
foreach (var d in deptAvgAge)
Console.WriteLine($"{d.Department}: 平均年齡 {d.AvgAge:F1}");
// 3. 扁平化:所有人的所有技能(去重)
var allSkills = _people
.SelectMany(p => p.Skills)
.Distinct()
.OrderBy(s => s);
Console.WriteLine("所有技能:" + string.Join(", ", allSkills));
// 4. 複雜查詢:IT 部門、年齡 30 以上、依 BMI 降序、取前 2 名
var topIt = _people
.Where(p => p.Department == "IT" && p.Age >= 30)
.OrderByDescending(p => p.Bmi)
.Take(2)
.Select(p => $"{p.Name} (BMI: {p.Bmi})");
Console.WriteLine("資深 IT 高 BMI:" + string.Join(", ", topIt));
// 5. 聚合:最年長者
var oldest = _people.OrderByDescending(p => p.Age).First();
Console.WriteLine($"最年長:{oldest.Name} ({oldest.Age} 歲)");
// 6. 量詞:是否所有人都會 C#
bool allKnowCSharp = _people.All(p => p.Skills.Contains("C#"));
Console.WriteLine($"全員會 C#:{allKnowCSharp}");
}
}
// 延遲執行陷阱範例
var query = people.Where(p => p.Age > 30); // 尚未執行
var count1 = query.Count(); // 執行一次
var count2 = query.Count(); // 再執行一次!
// 修正:具體化
var list = query.ToList();
var count1 = list.Count;
var count2 = list.Count;
from p in people // 來源
where p.Age > 30 // Where
orderby p.Name // OrderBy
group p by p.Dept into g // GroupBy
select new { g.Key, Count = g.Count() } // Select
join d in depts on p.DeptId equals d.Id // Join
let bmi = p.Weight / (p.Height * p.Height) // 區域變數
into g // 群組延續
IQueryable(EF Core 等)將查詢轉為 SQL 在資料庫端執行ToList() 具體化AsParallel()(PLINQ)或分頁 Skip/TakeSelect 只選需要的欄位,減少資料傳輸LINQ 不只是語法糖,更是將資料查詢邏輯內建於語言、提供型別安全與智慧提示的強大抽象。熟練掌握 LINQ 將大幅提升 C# 資料處理的開發效率與程式碼品質。