1.匿名函数
匿名函数是 C# 中无需显式定义方法名的代码块,可直接赋值给委托,大幅减少冗余代码,是 Lambda 表达式的前身。
- 定义匹配签名的委托类型
- 使用 delegate 关键字直接声明匿名代码块
- 将匿名函数赋值给委托变量并执行
匿名函数本质是编译器生成的无名方法,无需在类中单独定义具名方法,可直接捕获上下文变量,适合短生命周期的临时逻辑传递。
cs
// 1. 定义委托签名
delegate int MathOperation(int a, int b);
// 2. 声明匿名函数并赋值给委托
MathOperation multiply = delegate (int x, int y)
{
return x * y;
};
// 3. 执行匿名函数
int result = multiply(3, 4);
Console.WriteLine($"3*4的结果:{result}"); // 输出 12
// 结合集合筛选场景
int[] numbers = { 1, 2, 3, 4, 5, 6 };
var evenNums = Array.FindAll(numbers, delegate (int n)
{
return n % 2 == 0;
});
// 输出 2 4 6
foreach (var num in evenNums) Console.WriteLine(num);
2. Lambda 表达式
Lambda 是匿名函数的极简语法形式,用 => 符号替代 delegate 关键字,语法更简洁,是 Linq 与 Expression 的核心语法载体。
- 确认目标委托的参数数量与类型
- 按简化规则编写 Lambda 表达式
- 赋值给委托或直接作为方法参数传入
Lambda 可自动推断参数类型,单参数时可省略括号,单表达式时可省略大括号与 return,大幅压缩代码量,同时保留强类型检查特性。
cs
// 完整写法 → 逐步简化
// 1. 完整Lambda写法
Func<int, int, int> add1 = (int a, int b) => { return a + b; };
// 2. 省略参数类型(编译器自动推断)
Func<int, int, int> add2 = (a, b) => { return a + b; };
// 3. 单表达式省略大括号与return
Func<int, int, int> add3 = (a, b) => a + b;
// 单参数场景进一步简化
Action<string> printMsg = msg => Console.WriteLine($"消息:{msg}");
printMsg("Hello Lambda");
// 结合集合筛选
List<string> names = new List<string> { "Alice", "Bob", "Anna", "David" };
var aNames = names.Where(name => name.StartsWith("A"));
// 输出 Alice Anna
foreach (var name in aNames) Console.WriteLine(name);
3. Linq 表达式
Linq 是 .NET 内置的语言集成查询能力,提供声明式语法统一操作各类数据源,彻底解决不同数据场景下的语法割裂问题。
- 引入 System.Linq 命名空间
- 选择查询表达式语法或方法语法编写查询逻辑
- 执行查询获取结果
Linq 提供两种等价语法:类似 SQL 的查询表达式语法可读性更强,基于 Lambda 的方法语法更灵活,二者编译后生成的 IL 几乎完全一致。
cs
// 准备测试数据
int[] scores = { 97, 92, 81, 60, 75 };
// 写法1:查询表达式语法
var highScoresQuery = from score in scores
where score > 80
orderby score descending
select score;
// 写法2:方法语法(等价效果)
var highScoresMethod = scores
.Where(score => score > 80)
.OrderByDescending(score => score);
// 执行查询输出结果
// 输出 97 92
foreach (var s in highScoresQuery) Console.WriteLine(s);
4. 扩展方法
扩展方法可在不修改原有类源码的前提下,为已有类型添加新方法,是 Linq 链式调用能力的底层支撑机制。
- 定义静态非嵌套的扩展类
- 编写静态方法,第一个参数用 this 关键字标记要扩展的类型
- 引入扩展类的命名空间,即可像实例方法一样调用
扩展方法本质是静态方法的语法糖,编译器会将实例调用形式转换为静态方法调用,不会修改原类型的源码与结构。
cs
// 定义扩展类(必须是静态类)
namespace CustomExtensions
{
public static class StringExtension
{
// 为string类型扩展统计单词数量的方法
public static int WordCount(this string str)
{
return str.Split(new char[] { ' ', '.', '?' },
StringSplitOptions.RemoveEmptyEntries).Length;
}
}
}
// 调用端代码
using CustomExtensions;
string testStr = "The quick brown fox jumped over the lazy dog.";
int count = testStr.WordCount();
Console.WriteLine($"单词总数:{count}"); // 输出 9
5. Linq to Object
Linq to Object 是直接对内存集合(数组、List、Dictionary 等)执行 Linq 查询的模式,无需额外适配器,是日常开发最常用的 Linq 场景。
- 引入 System.Linq 命名空间
- 针对内存集合编写链式查询逻辑
- 调用 ToList() / ToArray() 等方法立即执行查询
Linq to Object 基于 IEnumerable<T> 接口实现,具备延迟执行特性:查询逻辑在遍历结果时才真正执行,可通过立即执行方法避免意外重复计算。
cs
// 定义测试实体
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
// 准备测试集合
List<Person> people = new List<Person>
{
new Person { Name = "Alice", Age = 25 },
new Person { Name = "Bob", Age = 30 },
new Person { Name = "Charlie", Age = 35 },
new Person { Name = "Anna", Age = 22 }
};
// 链式查询:筛选年龄>25 → 按年龄排序 → 提取姓名
var result = people
.Where(p => p.Age > 25)
.OrderBy(p => p.Age)
.Select(p => p.Name)
.ToList();
// 输出 Bob Charlie
foreach (var name in result) Console.WriteLine(name);
6. Expression表达式 动态拼接表达式目录树
Expression 表达式目录树是可遍历、可修改的代码抽象语法树,支持在运行时动态构建查询逻辑,是动态查询场景的核心方案。
- 引入 System.Linq.Expressions 命名空间
- 用 ParameterExpression 定义查询参数节点
- 逐层拼接常量、属性访问、二元运算等子节点
- 用 Expression.Lambda 封装为完整 Lambda 表达式树
表达式树不是可直接执行的代码,而是描述代码结构的对象树,每个节点都是强类型的 Expression 子类,可手动组合出任意复杂的查询逻辑。
cs
using System.Linq.Expressions;
// 目标:动态构建 p => p.Age >= 30 表达式
// 1. 定义参数节点:Person类型的参数p
ParameterExpression param = Expression.Parameter(typeof(Person), "p");
// 2. 拼接子节点:访问p.Age属性
MemberExpression ageProp = Expression.Property(param, "Age");
// 3. 拼接常量节点:30
ConstantExpression ageConst = Expression.Constant(30);
// 4. 拼接二元运算节点:p.Age >= 30
BinaryExpression greaterThan = Expression.GreaterThanOrEqual(ageProp, ageConst);
// 5. 封装为完整Lambda表达式树
Expression<Func<Person, bool>> lambdaExpr =
Expression.Lambda<Func<Person, bool>>(greaterThan, param);
// 编译为委托后执行
var filter = lambdaExpr.Compile();
var filteredPeople = people.Where(filter).ToList();
// 输出 Bob Charlie
foreach (var p in filteredPeople) Console.WriteLine(p.Name);
7. Expression解析表达式
表达式树的节点完全可遍历,可通过递归访问所有节点,实现表达式的读取、修改、转换等高级操作,是规则引擎、ORM 翻译的核心能力。
- 继承 ExpressionVisitor 自定义访问器
- 重写对应节点类型的访问方法
- 递归遍历整棵表达式树,完成解析或修改
.NET 内置的 ExpressionVisitor 提供了所有节点类型的默认访问实现,重写对应方法即可拦截节点访问过程,实现自定义解析逻辑。
cs
// 自定义访问器:解析表达式树并打印节点结构
public class ExpressionPrinter : ExpressionVisitor
{
protected override Expression VisitBinary(BinaryExpression node)
{
Console.WriteLine($"二元运算:{node.NodeType}");
return base.VisitBinary(node);
}
protected override Expression VisitMember(MemberExpression node)
{
Console.WriteLine($"访问成员:{node.Member.Name}");
return base.VisitMember(node);
}
protected override Expression VisitConstant(ConstantExpression node)
{
Console.WriteLine($"常量值:{node.Value}");
return base.VisitConstant(node);
}
}
// 使用解析器遍历之前构建的表达式树
var printer = new ExpressionPrinter();
printer.Visit(lambdaExpr);
// 输出:
// 访问成员:Age
// 常量值:30
// 二元运算:GreaterThanOrEqual
8. Expression扩展linq to everything
基于表达式树的动态拼接能力,可封装通用查询扩展方法,实现任意字段、任意条件的动态查询,适配 EF Core、内存集合等各类数据源,真正做到 Linq to Everything。
- 定义通用查询条件实体,封装字段名、操作符、值
- 编写条件解析方法,将条件转换为表达式树节点
- 用 Expression.AndAlso / OrElse 组合多个条件
- 封装为 IQueryable 的扩展方法,直接链式调用
基于表达式树的动态查询不会生成硬编码逻辑,可适配任意实体类型,同时保留强类型检查,避免 SQL 注入风险,大幅减少重复查询代码。
cs
// 定义通用查询条件类
public class QueryCondition
{
public string FieldName { get; set; }
public object Value { get; set; }
public string Operator { get; set; } // Equal/GreaterThan/LessThan
}
// 定义IQueryable的动态查询扩展方法
public static class LinqExtensions
{
public static IQueryable<T> DynamicWhere<T>(
this IQueryable<T> source,
List<QueryCondition> conditions)
{
if (conditions == null || conditions.Count == 0) return source;
ParameterExpression param = Expression.Parameter(typeof(T), "x");
Expression body = Expression.Constant(true);
foreach (var cond in conditions)
{
MemberExpression prop = Expression.Property(param, cond.FieldName);
ConstantExpression val = Expression.Constant(cond.Value);
BinaryExpression conditionExpr = cond.Operator switch
{
"Equal" => Expression.Equal(prop, val),
"GreaterThan" => Expression.GreaterThan(prop, val),
"LessThan" => Expression.LessThan(prop, val),
_ => throw new NotSupportedException("不支持的操作符")
};
body = Expression.AndAlso(body, conditionExpr);
}
var lambda = Expression.Lambda<Func<T, bool>>(body, param);
return source.Where(lambda);
}
}
// 调用示例:动态组合多个条件
var query = people.AsQueryable()
.DynamicWhere(new List<QueryCondition>
{
new QueryCondition{ FieldName = "Age", Value = 20, Operator = "GreaterThan" },
new QueryCondition{ FieldName = "Name", Value = "Alice", Operator = "Equal" }
})
.ToList();
// 输出 Alice
foreach (var p in query) Console.WriteLine(p.Name);