Expression 表达式树
什么是表达式树
表达式树以树形数据结构表示代码,其中每一个节点都是一种表达式,Expression<TDelegate>就是一个表达式目录树,里面是一个委托,例如Func<>,Action<>等等。
Expression可以通过Compile() 转换成委托,所以说要执行表达式树就通过Compile()转换成一个可执行的委托。
IQueryable 和 IEnumerable
Expression是IQueryable的扩展方法,IQueryable是Linq to Object , 而IEnumerable 是Linq to sql。
IQueryable 和 IEnumerable 两者都是延迟执行。
IQueryable 相当于是通过表达式渲染的 sql 语句,例如在ToList才会真正的查询数据库。
IEnumerable 是先加载在内存中,每次的筛选条件是通过内存去筛选的。
准备工作
先建一个类
public class Info
{
public Info( string _id,string _name, int _age)
{
Name = _name;
Age = _age;
Id = _id;
}
public string Name { get; set; }
public int Age { get; set; }
public string Id { get; set; }
}
构建一个稍微简单的表达式树
ParameterExpression param = Expression.Parameter(typeof(int), "param");
Expression body = Expression.LessThan(param,Expression.Constant(10));
Expression<Func<int, bool>> expr = Expression.Lambda<Func<int, bool>>(body, param);
Console.WriteLine(expr.Compile()(50));
//Prints False
使用工厂构建表达式树
ParameterExpression x = Expression.Parameter(typeof(Info), "x");
Expression body = Expression.Call(
Expression.Property(x, "Name"),
typeof(string).GetMethod("StartsWith", new[] { typeof(string) })!,
Expression.Constant("张")
);
var exp = Expression.Lambda<Func<Info, bool>>(body, x);
Console.WriteLine(exp.Compile()(new Info(_id:"1",_name: "张三1",_age: 10)));
//Prints True
解析表达式树
// Add the following using directive to your code file:
// using System.Linq.Expressions;
// Create an expression tree.
Expression<Func<int, bool>> exprTree = num => num < 5;
// Decompose the expression tree.
ParameterExpression param = (ParameterExpression)exprTree.Parameters[0];
BinaryExpression operation = (BinaryExpression)exprTree.Body;
ParameterExpression left = (ParameterExpression)operation.Left;
ConstantExpression right = (ConstantExpression)operation.Right;
Console.WriteLine("Decomposed expression: {0} => {1} {2} {3}",
param.Name, left.Name, operation.NodeType, right.Value);
// This code produces the following output:
// Decomposed expression: num => num LessThan 5
编译表达式树
// Creating an expression tree.
Expression<Func<int, bool>> expr = num => num < 5;
// Compiling the expression tree into a delegate.
Func<int, bool> result = expr.Compile();
// Invoking the delegate and writing the result to the console.
Console.WriteLine(result(4));
// Prints True.
// You can also use simplified syntax
// to compile and run an expression tree.
// The following line can replace two previous statements.
Console.WriteLine(expr.Compile()(4));
// Also prints True.
通过已有的lambda模拟通过表达式树生成
//模拟
Expression<Func<Info, bool>> predicate = c =>
c.Id.Equals("1")
&& c.Name == "张三1"
&& c.Age > 8;
Func<Info, bool> func = predicate.Compile();
bool bResult = func.Invoke(infos[0]);
ParameterExpression parm = Expression.Parameter(typeof(Info), "c");
Expression pre1 = Expression.Call(Expression.Property(parm, "Id"),
typeof(string).GetMethod("Equals", new[] { typeof(string) }),
Expression.Constant("1"));
Expression pre2 = Expression.Equal(Expression.Property(parm, "Name"), Expression.Constant("张三1"));
Expression pre3 = Expression.GreaterThan(Expression.Property(parm, "Age"), Expression.Constant(8));
Expression pre12= Expression.And(pre1, pre2);
Expression resPre=Expression.And(pre12, pre3);
Expression<Func<Info, bool>> expression = Expression.Lambda<Func<Info, bool>>(resPre, parm);
Console.WriteLine(expression.Compile()(new Info(_id:"1",_name: "张三1",_age: 10))); //Prints True
通过循环实现数字阶乘的表达式树
// Creating a parameter expression.
ParameterExpression value = Expression.Parameter(typeof(int), "value");
// Creating an expression to hold a local variable.
ParameterExpression result = Expression.Parameter(typeof(int), "result");
// Creating a label to jump to from a loop.
LabelTarget label = Expression.Label(typeof(int));
// Creating a method body.
BlockExpression block = Expression.Block(
// Adding a local variable.
new[] { result },
// Assigning a constant to a local variable: result = 1
Expression.Assign(result, Expression.Constant(1)),
// Adding a loop.
Expression.Loop(
// Adding a conditional block into the loop.
Expression.IfThenElse(
// Condition: value > 1
Expression.GreaterThan(value, Expression.Constant(1)),
// If true: result *= value --
Expression.MultiplyAssign(result,
Expression.PostDecrementAssign(value)),
// If false, exit the loop and go to the label.
Expression.Break(label, result)
),
// Label to jump to.
label
)
);
// Compile and execute an expression tree.
int factorial = Expression.Lambda<Func<int, int>>(block, value).Compile()(5);
Console.WriteLine(factorial);
// Prints 120.
扩展: 动态LinQ库
如果通过表达式构建比较复杂,这里扩展之后可以通过字符串直接写,例如在平时开发中可以把表达式直接通过字符串记录在数据库中,可以动态的根据表达式去筛选或者判断一些业务,不仅不会每次变动去改代码发版,还会减少不必要的大量代码,增加灵活性。
先引入包
Install-Package System.Linq.Dynamic.Core
List<Info> infos = new List<Info>(); infos.Add(new Info("1","张大", 10)); infos.Add(new Info("2","张二", 20)); infos.Add(new Info("3","张三", 30)); var res = infos.AsQueryable() .Where("Name.Contains(@0)","二") .ToList(); Console.WriteLine(res?.FirstOrDefault()?.Name); // Prints 张二
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构