Linq之Expression初见

简介:

目录

写在前面

系列文章

Expression

表达式树创建方式

一个例子

总结

写在前面

上篇文章介绍了扩展方法,这篇文章开始将陆续介绍在linq中使用最多的表达式树的相关概念,以概念及例子一一列出如何在代码中使用Expression。

系列文章

Linq之Lambda表达式初步认识

Linq之Lambda进阶

Linq之隐式类型、自动属性、初始化器、匿名类

Linq之扩展方法

Expression

还是老样子,首先看MSDN中对表达式树的描述

表达式树以树形数据结构表示代码,其中每一个节点都是一种表达式,比如方法调用和 x < y 这样的二元运算等。

你可以对表达式树中的代码进行编辑和运算。 这样能够动态修改可执行代码、在不同数据库中执行 LINQ 查询以及创建动态查询。 

表达式树又称为“表达式目录树”,以数据形式表示语言级代码,它是一种抽象语法树或者说是一种数据结构。

通过上面的描述,你会发现表达式树的作用:动态修改可执行代码、在不同数据库中执行Linq查询及创建动态查询。那它是如何做到的呢?那下面就开始咱们的表达式树之旅吧。

表达式树创建方式

表达式树创建方式分为两种:以lambda表达式的方式创建,通过API静态方法创建。

若 lambda 表达式被分配给 Expression<TDelegate> 类型的变量,则编译器可以发射代码以创建表示该 lambda 表达式的表达式树。

看一个例子:

1   static void Main(string[] args)
2         {
3             System.Linq.Expressions.Expression<Func<int, bool>> lambda = num => num >= 5;
4         }

上面的代码意思就以表达式目录树的形式将强类型的lambda表达式num=>num>=5标识为数据结构。

通过 API 创建表达式树需要使用 Expression 类。

该类包含创建特定类型表达式树节点的静态工厂方法,比如表示参数变量的 ParameterExpression,或者是表示方法调用的 MethodCallExpression。 System.Linq.Expressions 名称空间还解释了 ParameterExpression、MethodCallExpression和另一种具体表达式类型。 这些类型来源于抽象类型 Expression。

那么我使用API的方式创建上面例子中的表达式树:

说的很高大上,其实就是类Expression的一系列静态方法。

首先引入命名空间

using System.Linq.Expressions;
复制代码
 1         static void Main(string[] args)
 2         {
 3             //创建lambda表达式 num=>num>=5
 4             //第一步创建输入参数,参数名为num,类型为int类型
 5             ParameterExpression numParameter = Expression.Parameter(typeof(int), "num");
 6             //第二步创建常量表达式5,类型int
 7             ConstantExpression constant = Expression.Constant(5, typeof(int));
 8             //第三步创建比较运算符>=,大于等于,并将输入参数表达式和常量表达式输入
 9             //表示包含二元运算符的表达式。BinaryExpression继承自Expression
10             BinaryExpression greaterThanOrEqual = Expression.GreaterThanOrEqual(numParameter, constant);
11             //第四步构建lambda表达式树
12             //Expression.Lambda<Func<int, bool>>:通过先构造一个委托类型来创建一个 LambdaExpression
13             Expression<Func<int, bool>> lambda = Expression.Lambda<Func<int, bool>>(greaterThanOrEqual, numParameter);
14         }
复制代码

 

通过上面的代码你会发现这种方式在创建的时候,lambda表达式的左右及二元运算符都要分别的创建,然后在通过Expression.Lambda方法构建lambda表达式。

一个例子

在 .NET Framework 4 中,API 表达式树还支持赋值表达式和控制流表达式,比如循环、条件块和 try-catch 块等。

看一个例子,通过API表达式树创建一个利用循环求1到n的和的表达式树。

如果能这样写该有多好啊

复制代码
1             Expression<Func<int, int>> lambda = n =>
2             {
3                 int result = 0;
4                 for (int j = n; j >= 0; j--)
5                 {
6                     result += j;
7                 }
8                 return result;
9             };
复制代码

可惜

通过API创建表达式树,可以创建更为复杂的表达式树,这里先尝尝鲜

复制代码
 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             //变量表达式
 6             ParameterExpression i = Expression.Variable(typeof(int), "i");
 7             //变量表达式
 8             ParameterExpression sum = Expression.Variable(typeof(int), "sum");
 9             //跳出循环标志
10             LabelTarget label = Expression.Label(typeof(int));
11             //块表达式
12             BlockExpression block =
13                 Expression.Block(
14                 //添加局部变量
15                     new[] { sum },
16                 //为sum赋初值 sum=1
17                 //Assign表示赋值运算符
18                     Expression.Assign(sum, Expression.Constant(1, typeof(int))),
19                 //loop循环
20                     Expression.Loop(
21                 //如果为true 然后求和,否则跳出循环
22                         Expression.IfThenElse(
23                 //如果i>=0
24                         Expression.GreaterThanOrEqual(i, Expression.Constant(0, typeof(int))),
25                 //sum=sum+i;i++;
26                                   Expression.AddAssign(sum, Expression.PostDecrementAssign(i)),
27                 //跳出循环
28                             Expression.Break(label, sum)
29                         ), label
30                      )  // Loop ends
31                  );
32             int resutl = Expression.Lambda<Func<int, int>>(block, i).Compile()(100);
33             Console.WriteLine(resutl);
34             Console.Read();
35         }
36     }
复制代码

输出结果

总结

本篇文章主要介绍了表达式树的概念及两种创建方式。在文章的结尾给出了一个例子,也是先尝尝鲜,对于代码中的一些静态方法可先参考注释。下篇文章将介绍一些Expression的常用的静态方法。

参考文章

http://msdn.microsoft.com/zh-cn/library/bb397951.aspx

博客地址: http://www.cnblogs.com/wolf-sun/
博客版权: 本文以学习、研究和分享为主,欢迎转载,但必须在文章页面明显位置给出原文连接。
如果文中有不妥或者错误的地方还望高手的你指出,以免误人子弟。如果觉得本文对你有所帮助不如【推荐】一下!如果你有更好的建议,不如留言一起讨论,共同进步!
再次感谢您耐心的读完本篇文章。http://www.cnblogs.com/wolf-sun/p/4222473.html

相关文章
|
编解码 网络协议 开发工具
GB/T28181-2022协议版本标识X-GB-Ver解读
GB28181-2022相对2016,其中有个变化是:报文中携带协议版本标识 X-GB-Ver:3.0(3.0-2022 2.0-2016)
664 0
|
7月前
|
人工智能 Rust 自然语言处理
Qoder NEXT 测评:不止是代码补全,而是“会思考的编程搭档”
本次测评聚焦三大核心问题: 能否超越传统 FIM,支持真实开发中的结构化编辑? 编辑建议是否精准、符合开发者意图? 是否具备持续进化能力,越用越好?
|
10月前
|
缓存 运维 监控
《SaaS网关多租户治理:从串流到稳控的实践》
本文记录某制造集团SaaS协同平台API网关多租户治理的重构实践。初代网关因依赖“路径前缀+静态IP映射”,在租户增至8家(含3家私有云部署)后,爆发数据串流、混合云适配差、个性化需求迭代慢、故障定位难四大问题。通过搭建“租户元数据+动态路由表”双层隔离机制解决串流,设计多维度决策的混合云路由策略引擎降低转发延迟,构建配置化规则引擎实现零代码定制,并攻克缓存穿透、路由断连、规则冲突三大细节难题。最终租户串流率归零,混合云路由延迟降45%,规则生效时间从2天缩至10秒。
564 9
《SaaS网关多租户治理:从串流到稳控的实践》
|
9月前
|
机器学习/深度学习 人工智能 监控
番茄叶片病害检测数据集(千张图片已划分)| AI训练适用于目标检测任务
在农业领域,植物病害检测是确保作物健康和提高农业生产效率的关键任务之一。随着计算机视觉技术的快速发展,基于深度学习的目标检测方法成为了病害识别的主流手段。为此,专门针对番茄叶片病害检测任务,我们推出了一个经过精心设计的番茄叶片病害检测数据集。该数据集包含了10,853张带标签的图像,覆盖了10种常见的番茄叶片病害类型,支持YOLO等先进的目标检测模型训练,旨在帮助研究人员和开发者提高农作物病害自动化检测的能力。
1383 40
番茄叶片病害检测数据集(千张图片已划分)| AI训练适用于目标检测任务
|
前端开发
如何在Promise.race()中处理超时后的操作?
如何在Promise.race()中处理超时后的操作?
598 163
|
NoSQL Redis 数据安全/隐私保护
redis设置密码
redis设置密码
2260 1
|
存储 关系型数据库 MySQL
【阿里规约】阿里开发手册解读——数据库和ORM篇
从命名规范、建表规范、查询规范、索引规范、操作规范等角度出发,详细阐述MySQL数据库使用过程中所需要遵循的各种规范。
【阿里规约】阿里开发手册解读——数据库和ORM篇
|
设计模式 移动开发 Java
【阿里规约】阿里开发手册解读——代码格式篇
本文所有代码格式规范遵循《阿里规约》,从编码、换行符、空格规则、括号规则、字符数等方面展开,详细阐述方法参数、强制转换、运算符、缩进等元素的编写规范。
【阿里规约】阿里开发手册解读——代码格式篇
|
物联网 C#
【C#】简单的蓝牙通讯功能实现
【C#】简单的蓝牙通讯功能实现
1169 0
|
Oracle 关系型数据库 数据库
Oracle数据库协议适配器错误解决方法
Oracle数据库协议适配器错误解决方法
2375 2