Linq
一、Lambda 表达式(C# 函数式编程基础)
Lambda 是简化委托(Delegate) 调用的语法糖,让代码更简洁,是 LINQ 的核心语法工具。
-
委托是 “方法的引用类型”,可将方法当作参数传递。例如:
// 声明委托(匹配“接收 int,返回 bool”的方法签名) delegate bool MyDelegate(int x); // 方法示例 bool IsEven(int num) => num % 2 == 0; // 委托实例化并指向方法 MyDelegate del = new MyDelegate(IsEven); bool result = del(4); // 调用委托,实际执行 IsEven(4) -
Lambda 表达式写法 用
=>(Lambda 操作符)简化委托的使用,格式为(参数) => 表达式/语句块。- 替代上述委托示例:
MyDelegate del = x => x % 2 == 0; // 直接用 Lambda 定义“判断偶数”的逻辑 bool result = del(4); // 结果为 true- 多参数 / 语句块示例:
// 多参数 Func<int, int, int> add = (a, b) => a + b; // 语句块(需用 {} 包裹,且需 return 显式返回) Func<int, string> describe = num => { if (num > 0) return "正数"; return "非正数"; }; -
Lambda 简化规则
- 参数类型可省略(编译器自动推断,即 “隐式类型”):
// 等同于 (int x) => x > 10 Func<int, bool> isLarge = x => x > 10;- 单个参数可省略括号:
// 等同于 (x) => x * 2 Func<int, int> doubleIt = x => x * 2;- 单行表达式可省略
return和{}:
// 等同于 num => { return num % 2 == 0; } Func<int, bool> isEven = num => num % 2 == 0; -
隐式类型
var让编译器自动推断变量类型,简化声明。常与 Lambda、LINQ 结合: -
匿名类 无需显式定义类,直接创建 “临时对象”,常用于 LINQ 的投影操作(后文 “9. 投影操作”):
var person = new { Name = "Alice", Age = 25 }; // 匿名类实例
Console.WriteLine(person.Name); // 可直接访问属性
-
C# 扩展方法 为现有类型(如
string、List<T>)“新增方法”,但无需修改类型源码,是 LINQ 能为IEnumerable<T>扩展Where/Select等查询方法的核心机制。- 定义示例(为
string扩展IsNullOrEmpty方法):
public static class StringExtensions { public static bool IsNullOrEmpty(this string str) { return string.IsNullOrEmpty(str); } } // 使用: string s = null; bool result = s.IsNullOrEmpty(); // 等价于 string.IsNullOrEmpty(s) - 定义示例(为
二、LINQ(语言集成查询)—— 基于扩展方法的数据查询
LINQ 依托扩展方法和Lambda 表达式,为集合(List<T>、数组等)、数据库、XML 等提供 “统一的查询语法”,核心是对 IEnumerable<T> 接口的扩展。
6.1 数据过滤(Where 方法)
筛选集合中符合条件的元素,返回 IEnumerable<T>。
var numbers = new List<int> { 1, 2, 3, 4, 5 };
var evenNumbers = numbers.Where(n => n % 2 == 0); // 结果:[2,4]
6.2 获取数据条数(Count 方法)
统计集合中符合条件的元素数量,返回 int。
int count = numbers.Count(n => n > 2); // 结果:3(元素 3、4、5)
6.3 Any 方法使用
判断集合中是否存在符合条件的元素,返回 bool(性能更优,无需遍历全部元素)。
bool hasEven = numbers.Any(n => n % 2 == 0); // 结果:true
6.4 获取一条数据(First/FirstOrDefault/Single 等)
-
First():获取第一个符合条件的元素,无匹配时抛异常; -
FirstOrDefault():获取第一个符合条件的元素,无匹配时返回类型默认值(如int为 0,引用类型为null); -
Single():集合中仅有一个符合条件的元素时返回,否则抛异常(用于确保 “唯一结果” 场景)。
int firstEven = numbers.First(n => n % 2 == 0); // 结果:2
int? firstOddOrDefault = numbers.FirstOrDefault(n => n % 2 == 1); // 结果:1
6.5 排序(OrderBy/OrderByDescending)
对集合按指定规则升序 / 降序排列,返回排序后的 IEnumerable<T>。
var sorted = numbers.OrderBy(n => n); // 升序:[1,2,3,4,5]
var sortedDesc = numbers.OrderByDescending(n => n); // 降序:[5,4,3,2,1]
6.6 限制结果集(Take/Skip)
-
Take(n):取前n个元素; -
Skip(n):跳过前n个元素,取剩余元素。 常结合使用实现 “分页”。
var top2 = numbers.Take(2); // 结果:[1,2]
var skip2 = numbers.Skip(2); // 结果:[3,4,5]
var page2 = numbers.Skip(2).Take(2); // 跳过前 2 个,取 2 个:[3,4]
6.7 聚合函数(Sum/Min/Max/Average 等)
对集合进行 “聚合计算”,如求和、求最大 / 最小值、平均值等。
int sum = numbers.Sum(); // 结果:15
int max = numbers.Max(); // 结果:5
double avg = numbers.Average(); // 结果:3.0
6.8 分组(GroupBy)
将集合按指定键分组,返回 IEnumerable<IGrouping<TKey, TElement>>,IGrouping 可理解为 “键 + 分组内元素的集合”。
var people = new List<Person> {
new Person { Name = "Alice", Age = 25 },
new Person { Name = "Bob", Age = 30 },
new Person { Name = "Charlie", Age = 25 }
};
var groupedByAge = people.GroupBy(p => p.Age);
// 遍历分组:
foreach (var group in groupedByAge) {
Console.WriteLine($"年龄 {group.Key} 的人:");
foreach (var person in group) {
Console.WriteLine(person.Name);
}
}
// 输出:
// 年龄 25 的人:
// Alice
// Charlie
// 年龄 30 的人:
// Bob
6.9 投影操作(Select)
将集合中的元素 “转换 / 映射” 为新的形式(如匿名类、其他类型),是 LINQ 中 “数据重塑” 的核心方法。
var names = people.Select(p => p.Name); // 投影为姓名集合:["Alice","Bob","Charlie"]
var anonymous = people.Select(p => new {
PersonName = p.Name,
AgeCategory = p.Age > 25 ? "年长" : "年轻"
}); // 投影为匿名类集合
6.10 链式调用
LINQ 方法返回的都是 IEnumerable<T>(或其衍生类型),因此可连续调用多个 LINQ 方法,逐步筛选 / 转换数据。
var result = numbers
.Where(n => n % 2 == 0) // 筛选偶数
.OrderBy(n => n) // 升序排列
.Select(n => n * 2) // 每个数乘 2
.Take(1); // 取第一个
// 结果:4(原偶数 [2,4] → 排序后 [2,4] → 乘 2 后 [4,8] → 取第一个 4)
6.11 LINQ 的另一种写法(查询表达式)
除了 “方法语法”(如 Where/Select 链式调用),LINQ 还支持查询表达式(类似 SQL 语法),编译器会将其转换为方法语法执行。
// 方法语法:
var evenNums1 = numbers.Where(n => n % 2 == 0);
// 查询表达式:
var evenNums2 = from n in numbers
where n % 2 == 0
select n;
// 两者完全等价,结果均为 [2,4]
浙公网安备 33010602011771号