带你一文了解C#中的Expression
原文网址:https://www.jb51.net/article/231755.htm
我们书接上文,我们在了解LINQ下面有说到在本地查询IEnumerbale主要是用委托来作为传参,而解析型查询
IQueryable则用Expression来作为传参:
1
2
3
|
public static IEnumerable<T> Where<T>( this IEnumerable<T> enumable, Func<T, bool > func) public static IQueryable<T> Where<T>( this IQueryable<T> queryable, Expression<Func<T, bool >> func) |
那么我们就来聊聊有关表达式Expression里面的东西吧
Expression与Expression Tree
首先我们来写下一些代码:
1
2
3
4
5
|
Expression<Func< int , int >> expression = (num) => num + 5; Console.WriteLine($ "NodeType:{expression.NodeType}" ); Console.WriteLine($ "Body:{expression.Body}" ); Console.WriteLine($ "Body Type: {expression.Body.GetType()}" ); Console.WriteLine($ "Body NodeType: {expression.Body.NodeType}" ); |
输出如下:
NodeType:Lambda
Body:(num + 5)
Body Type: System.Linq.Expressions.SimpleBinaryExpression
Body NodeType: Add
我们将expression转为LambdaExpression看看都有啥:
1
2
3
4
5
6
7
8
|
if (expression.NodeType == ExpressionType.Lambda) { var lambda = (LambdaExpression)expression; var parameter = lambda.Parameters.Single(); Console.WriteLine($ "parameter.Name:{parameter.Name}" ); Console.WriteLine($ "parameter.Type:{parameter.Type}" ); Console.WriteLine($ "parameter.ReturnType:{lambda.ReturnType}" ); } |
输出如下:
parameter.Name:num
parameter.Type:System.Int32
parameter.ReturnType:System.Int32
由于我们知道expression.Body是BinaryExpression,那么我们就将其转为它,然后我们继续看下去:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
if (expression.Body.NodeType == ExpressionType.Add) { var binaryExpreesion = (BinaryExpression)expression.Body; Console.WriteLine($ "Left Type:{binaryExpreesion.Left.GetType()}" ); Console.WriteLine($ "Left NodeType:{binaryExpreesion.Left.NodeType}" ); Console.WriteLine($ "Right Type:{binaryExpreesion.Right.GetType()}" ); Console.WriteLine($ "Right NodeType:{binaryExpreesion.Right.NodeType}" ); if (binaryExpreesion.Left is ParameterExpression parameterExpreesion) { Console.WriteLine($ "parameterExpreesion.Name:{parameterExpreesion.Name}" ); Console.WriteLine($ "parameterExpreesion.Type:{parameterExpreesion.Type}" ); } if (binaryExpreesion.Right is ConstantExpression constantExpreesion) { Console.WriteLine($ "constantExpreesion.Value:{constantExpreesion.Value}" ); } } |
输出如下:
Left Type:System.Linq.Expressions.PrimitiveParameterExpression`1[System.Int32]
Left NodeType:Parameter
Right Type:System.Linq.Expressions.ConstantExpression
Right NodeType:Constant
parameterExpreesion.Name:num
parameterExpreesion.Type:System.Int32
constantExpreesion.Value:5
最后我们将表达式树转为委托:
1
2
|
var @ delegate = expression.Compile(); Console.WriteLine(@ delegate ?.Invoke(2)); |
输出:
7 //2+5
实际上,通过Expression<Func<int, int>> expression = (num) => num + 5;,赋值后的expression 变成了一个表达式树,它的结构是这样的:
而有意思的是二元表达式树BinaryExpression是一个二叉树,而LambdaExpression则是一个支持参数的表达式,能够通过其Parameters属性知道传入的参数的类型和数量,通过ReturnType知道返回值是什么类型
而我们再看看整个关于Expression的继承关系链:
因此,我们也可以显式的通过各自Expreesion的实现子类来创建跟lambda表达式一样的结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
var parameterExpreesion1 = Expression.Parameter( typeof ( int ), "num" ); BinaryExpression binaryExpression1 = Expression.MakeBinary(ExpressionType.Add, parameterExpreesion1, Expression.Constant(5)); Expression<Func< int , int >> expression1 = Expression.Lambda<Func< int , int >>(binaryExpression1, parameterExpreesion1); if (expression1.Body.NodeType == ExpressionType.Add) { var binaryExpreesion1 = (BinaryExpression)expression1.Body; Console.WriteLine($ "Left Type:{binaryExpreesion1.Left.GetType()}" ); Console.WriteLine($ "Left NodeType:{binaryExpreesion1.Left.NodeType}" ); Console.WriteLine($ "Right Type:{binaryExpreesion1.Right.GetType()}" ); Console.WriteLine($ "Right NodeType:{binaryExpreesion1.Right.NodeType}" ); if (binaryExpreesion1.Left is ParameterExpression parameterExpreesion2) { Console.WriteLine($ "parameterExpreesion.Name:{parameterExpreesion2.Name}" ); Console.WriteLine($ "parameterExpreesion.Type:{parameterExpreesion2.Type}" ); } if (binaryExpreesion1.Right is ConstantExpression constantExpreesion1) { Console.WriteLine($ "constantExpreesion.Value:{constantExpreesion1.Value}" ); } var @delegate1 = expression1.Compile(); Console.WriteLine(@delegate1(2)); |
输出结果:
Left Type:System.Linq.Expressions.PrimitiveParameterExpression`1[System.Int32]
Left NodeType:Parameter
Right Type:System.Linq.Expressions.ConstantExpression
Right NodeType:Constant
parameterExpreesion.Name:num
parameterExpreesion.Type:System.Int32
constantExpreesion.Value:5
result:7
我们则发现,结果是一模一样的,但是费劲了很多,因此用lamda构建表达式树是一个非常愉快的语法糖,让你能够愉快的在使用表达式和表达式树
参考
- 《C#7.0核心技术指南》
源码
BlogCodeSample/ExpressionSample at main · ZhengDaoWang/BlogCodeSample
总结
到此这篇关于C#中Expression的文章就介绍到这了,更多相关C#的Expression内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构