全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

C# 表达式树Expression Trees的知识梳理

目录

  • 简介
  • Lambda 表达式创建表达式树
  • API 创建表达式树
  • 解析表达式树
  • 表达式树的永久性
  • 编译表达式树
  • 执行表达式树
  • 修改表达式树
  • 调试

简介

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

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

表达式树还能用于动态语言运行时 (DLR) 以提供动态语言和 .NET Framework 之间的互操作性。

一、Lambda 表达式创建表达式树

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

C# 编译器只能从表达式 lambda (或单行 lambda)生成表达式树。

下列代码示例使用关键字 Expression创建表示 lambda 表达式:

 Expression<Action<int>> actionExpression = n => Console.WriteLine(n);
 Expression<Func<int, bool>> funcExpression1 = (n) => n < 0;
 Expression<Func<int, int, bool>> funcExpression2 = (n, m) => n - m == 0;

二、API 创建表达式树

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

下列代码示例展示如何通过 API 创建表示 lambda 表达式:num => num == 0

//通过 Expression 类创建表达式树
 // lambda:num => num == 0
 ParameterExpression pExpression = Expression.Parameter(typeof(int)); //参数:num
 ConstantExpression cExpression = Expression.Constant(0); //常量:0
 BinaryExpression bExpression = Expression.MakeBinary(ExpressionType.Equal, pExpression, cExpression); //表达式:num == 0
 Expression<Func<int, bool>> lambda = Expression.Lambda<Func<int, bool>>(bExpression, pExpression); //lambda 表达式:num => num == 0

代码使用Expression 类的静态方法进行创建。

三、解析表达式树

下列代码示例展示如何分解表示 lambda 表达式 num => num == 0 的表达式树。

Expression<Func<int, bool>> funcExpression = num => num == 0;
 //开始解析
 ParameterExpression pExpression = funcExpression.Parameters[0]; //lambda 表达式参数
 BinaryExpression body = (BinaryExpression)funcExpression.Body; //lambda 表达式主体:num == 0
 Console.WriteLine($"解析:{pExpression.Name} => {body.Left} {body.NodeType} {body.Right}");

四、表达式树永久性

表达式树应具有永久性(类似字符串)。这意味着如果你想修改某个表达式树,则必须复制该表达式树然后替换其中的节点来创建一个新的表达式树。  你可以使用表达式树访问者遍历现有表达式树。第七节介绍了如何修改表达式树。

五、编译表达式树

Expression<TDelegate> 类型提供了 Compile 方法以将表达式树表示的代码编译成可执行委托。

//创建表达式树
 Expression<Func<string, int>> funcExpression = msg => msg.Length;
 //表达式树编译成委托
 var lambda = funcExpression.Compile();
 //调用委托
 Console.WriteLine(lambda("Hello, World!"));
 //语法简化
 Console.WriteLine(funcExpression.Compile()("Hello, World!"));

六、执行表达式树

执行表达式树可能会返回一个值,也可能仅执行一个操作(例如调用方法)。

只能执行表示 lambda 表达式的表达式树。表示 lambda 表达式的表达式树属于 LambdaExpression 或 Expression<TDelegate> 类型。若要执行这些表达式树,需要调用 Compile 方法来创建一个可执行委托,然后调用该委托。

const int n = 1;
 const int m = 2;
 //待执行的表达式树
 BinaryExpression bExpression = Expression.Add(Expression.Constant(n), Expression.Constant(m));
 //创建 lambda 表达式
 Expression<Func<int>> funcExpression = Expression.Lambda<Func<int>>(bExpression);
 //编译 lambda 表达式
 Func<int> func = funcExpression.Compile();
 //执行 lambda 表达式
 Console.WriteLine($"{n} + {m} = {func()}");

七、修改表达式树

该类继承 ExpressionVisitor 类,通过 Visit 方法间接调用 VisitBinary 方法将 != 替换成 ==。基类方法构造类似于传入的表达式树的节点,但这些节点将其子目录树替换为访问器递归生成的表达式树。 

internal class Program
 {
 private static void Main(string[] args)
 {
 Expression<Func<int, bool>> funcExpression = num => num == 0;
 Console.WriteLine($"Source: {funcExpression}");
 var visitor = new NotEqualExpressionVisitor();
 var expression = visitor.Visit(funcExpression);
 Console.WriteLine($"Modify: {expression}");
 Console.Read();
 }
 /// <summary>
 /// 不等表达式树访问器
 /// </summary>
 public class NotEqualExpressionVisitor : ExpressionVisitor
 {
 public Expression Visit(BinaryExpression node)
 {
 return VisitBinary(node);
 }
 protected override Expression VisitBinary(BinaryExpression node)
 {
 return node.NodeType == ExpressionType.Equal
  ? Expression.MakeBinary(ExpressionType.NotEqual, node.Left, node.Right) //重新弄个表达式:用 != 代替 ==
  : base.VisitBinary(node);
 }
 }
 }

八、调试

8.1 参数表达式

 ParameterExpression pExpression1 = Expression.Parameter(typeof(string));
 ParameterExpression pExpression2 = Expression.Parameter(typeof(string), "msg");

图8-1

图8-2

从 DebugView 可知,如果参数没有名称,则会为其分配一个自动生成的名称。

 const int num1 = 250;
 const float num2 = 250;
 ConstantExpression cExpression1 = Expression.Constant(num1);
 ConstantExpression cExpression2 = Expression.Constant(num2);

图8-3

图8-4

从 DebugView 可知,float 比 int 多了个后缀 F。

 Expression lambda1 = Expression.Lambda<Func<int>>(Expression.Constant(250));
 Expression lambda2 = Expression.Lambda<Func<int>>(Expression.Constant(250), "CustomName", null);

图8-5

图8-6

观察 DebugView ,如果 lambda 表达式没有名称,则会为其分配一个自动生成的名称。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!


# C#  # 表达式树  # C#之Expression表达式树实例  # C#表达式树Expression动态创建表达式  # 浅谈c#表达式树Expression简单类型比较demo  # C#表达式树Expression基础讲解  # C#表达式树的基本用法讲解  # C#表达式树讲解  # C#表达式树基础教程  # C#执行表达式树(Expression Tree)的具体使用  # C#表达式树(Expression Trees)的使用  # 可执行  # 为其  # 递归  # 则会  # 创建一个  # 自动生成  # 都是  # 编译成  # 你可以  # 还能  # 遍历  # 你想  # 将其  # 数据结构  # 你可  # 类似于  # 方法来  # 以对  # 若要  # 数据库中 


相关文章: 建站之星安装需要哪些步骤及注意事项?  企业宣传片制作网站有哪些,传媒公司怎么找企业宣传片项目?  建站主机如何选?性能与价格怎样平衡?  如何在IIS中新建站点并配置端口与IP地址?  非常酷的网站设计制作软件,酷培ai教育官方网站?  网站制作多少钱一个,建一个论坛网站大约需要多少钱?  php8.4新语法match怎么用_php8.4match表达式替代switch【方法】  详解jQuery停止动画——stop()方法的使用  建站主机选择指南:服务器配置与SEO优化实战技巧  如何在香港免费服务器上快速搭建网站?  如何确保FTP站点访问权限与数据传输安全?  上海制作企业网站有哪些,上海有哪些网站可以让企业免费发布招聘信息?  哈尔滨网站建设策划,哈尔滨电工证查询网站?  网站设计制作企业有哪些,抖音官网主页怎么设置?  建站之星24小时客服电话如何获取?  济南网站制作的价格,历城一职专官方网站?  商务网站制作工程师,从哪几个方面把握电子商务网站主页和页面的特色设计?  如何用景安虚拟主机手机版绑定域名建站?  购物网站制作公司有哪些,哪个购物网站比较好?  大同网页,大同瑞慈医院官网?  建站之星价格显示格式升级,你的预算足够吗?  建站主机功能解析:服务器选择与快速搭建指南  济南专业网站制作公司,济南信息工程学校怎么样?  深圳 网站制作,深圳招聘网站哪个比较好一点啊?  制作网站外包平台,自动化接单网站有哪些?  建站之星后台密码遗忘如何找回?  建站之星如何防范黑客攻击与数据泄露?  广州美橙建站如何快速搭建多端合一网站?  ui设计制作网站有哪些,手机UI设计网址吗?  高配服务器限时抢购:企业级配置与回收服务一站式优惠方案  如何在Golang中使用replace替换模块_指定本地或远程路径  如何在阿里云高效完成企业建站全流程?  如何快速搭建自助建站会员专属系统?  香港服务器建站指南:外贸独立站搭建与跨境电商配置流程  网站制作培训多少钱一个月,网站优化seo培训课程有哪些?  武汉网站如何制作,黄黄高铁武穴北站途经哪些村庄?  香港服务器租用费用高吗?如何避免常见误区?  视频网站制作教程,怎么样制作优酷网的小视频?  如何在Golang中实现微服务服务拆分_Golang微服务拆分与接口管理方法  如何快速上传建站程序避免常见错误?  建站之星如何助力企业快速打造五合一网站?  如何通过wdcp面板快速创建网站?  如何在七牛云存储上搭建网站并设置自定义域名?  免费网站制作appp,免费制作app哪个平台好?  建站主机选购指南:核心配置优化与品牌推荐方案  如何选择服务器才能高效搭建专属网站?  如何在企业微信快速生成手机电脑官网?  如何高效完成自助建站业务培训?  小建面朝正北,A点实际方位是否存在偏差?  如何在阿里云通过域名搭建网站? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。