LINQ 与查询

翻译整理自 LINQ 与 Standard query operators。

1. 查询语法 vs 方法语法

var nums = new[] { 1, 2, 3, 4, 5 };

// 查询语法
var evens = from x in nums
            where x % 2 == 0
            select x * x;

// 方法语法
var evens2 = nums
    .Where(x => x % 2 == 0)
    .Select(x => x * x);

2. 常用运算符

nums.Where(x => x > 2);
nums.Select(x => x * 2);
nums.OrderBy(x => x);
nums.OrderByDescending(x => x);
nums.GroupBy(x => x % 2);
nums.Distinct();
nums.Take(3);
nums.Skip(2);
nums.First();
nums.FirstOrDefault();
nums.Any(x => x > 3);
nums.All(x => x > 0);
nums.Count();
nums.Sum();
nums.Average();
nums.Min(); nums.Max();
nums.Contains(3);
nums.Concat(other);
nums.Zip(other, (a, b) => a + b);
nums.Aggregate((a, b) => a + b);

3. 投影与匿名类型

var result = users
    .Select(u => new { u.Name, u.Age });
foreach (var r in result)
    Console.WriteLine($"{r.Name} {r.Age}");

4. 多源 join

var orders = users.Join(
    items,
    u => u.Id,
    i => i.UserId,
    (u, i) => new { u.Name, i.Name });

// 查询语法
var o = from u in users
        join i in items on u.Id equals i.UserId
        select new { u.Name, i.Name };

5. GroupJoin

var groups = from u in users
             join i in items on u.Id equals i.UserId into g
             select new { u.Name, Items = g };

6. 排序与分组

var sorted = nums.OrderBy(x => x).ThenByDescending(x => x);
var grouped = nums.GroupBy(x => x % 2)
                  .Select(g => new { Mod = g.Key, Sum = g.Sum() });

7. ToList / ToDictionary

var list = nums.Where(x => x > 2).ToList();
var dict = users.ToDictionary(u => u.Id);
var set  = users.ToHashSet();
var arr  = nums.ToArray();

8. 延迟执行

LINQ 查询默认惰性求值:

var q = nums.Where(x => x > 2);
nums.Add(10);                       // 修改源
foreach (var x in q) Console.WriteLine(x);   // 包含 10

强制立即求值:ToList、ToArray、Count 等。

9. Enumerable.Range 与 Repeat

var r = Enumerable.Range(1, 10);
var rep = Enumerable.Repeat("x", 5);

10. LINQ to XML / JSON

using System.Xml.Linq;

var doc = XDocument.Parse("<root><item id='1'/></root>");
var ids = doc.Descendants("item")
             .Select(e => (int)e.Attribute("id"));

11. 表达式树与 IQueryable

IQueryable<T> 把 lambda 编译为表达式树,由 provider 翻译为目标查询(如 SQL):

// EF Core
var users = dbContext.Users
    .Where(u => u.Age > 18)
    .OrderBy(u => u.Name)
    .ToList();   // 翻译为 SQL 执行

12. PLINQ 并行

var r = nums.AsParallel()
            .Where(x => x > 2)
            .Select(x => x * 2);

小结

LINQ 让查询、过滤、投影、分组像 SQL 一样优雅,是 C# 的杀手锏特性。