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

发布时间 - 2026-01-10 22:17:49    点击率:

目录

  • 简介
  • 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)的使用  # 可执行  # 为其  # 递归  # 则会  # 创建一个  # 自动生成  # 都是  # 编译成  # 你可以  # 还能  # 遍历  # 你想  # 将其  # 数据结构  # 你可  # 类似于  # 方法来  # 以对  # 若要  # 数据库中 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 网站制作大概多少钱一个,做一个平台网站大概多少钱?  如何在万网ECS上快速搭建专属网站?  如何快速查询网址的建站时间与历史轨迹?  VIVO手机上del键无效OnKeyListener不响应的原因及解决方法  香港服务器网站测试全流程:性能评估、SEO加载与移动适配优化  魔毅自助建站系统:模板定制与SEO优化一键生成指南  Laravel中Service Container是做什么的_Laravel服务容器与依赖注入核心概念解析  js代码实现下拉菜单【推荐】  Laravel如何使用Gate和Policy进行权限控制_Laravel权限判定与策略规则配置  Laravel如何获取当前用户信息_Laravel Auth门面获取用户ID  Laravel如何实现全文搜索_Laravel Scout集成Algolia或Meilisearch教程  Laravel项目怎么部署到Linux_Laravel Nginx配置详解  javascript事件捕获机制【深入分析IE和DOM中的事件模型】  Laravel如何配置和使用缓存?(Redis代码示例)  php嵌入式断网后怎么恢复_php检测网络重连并恢复硬件控制【操作】  制作无缝贴图网站有哪些,3dmax无缝贴图怎么调?  网站广告牌制作方法,街上的广告牌,横幅,用PS还是其他软件做的?  Laravel怎么生成URL_Laravel路由命名与URL生成函数详解  厦门模型网站设计制作公司,厦门航空飞机模型掉色怎么办?  ,网页ppt怎么弄成自己的ppt?  Python面向对象测试方法_mock解析【教程】  利用python获取某年中每个月的第一天和最后一天  如何打造高效商业网站?建站目的决定转化率  公司门户网站制作公司有哪些,怎样使用wordpress制作一个企业网站?  如何在新浪SAE免费搭建个人博客?  七夕网站制作视频,七夕大促活动怎么报名?  Laravel的Blade指令怎么自定义_创建你自己的Laravel Blade Directives  php结合redis实现高并发下的抢购、秒杀功能的实例  如何用ChatGPT准备面试 模拟面试问答与职场话术练习教程  如何为不同团队 ID 动态生成多个独立按钮  专业企业网站设计制作公司,如何理解商贸企业的统一配送和分销网络建设?  Laravel怎么做数据加密_Laravel内置Crypt门面的加密与解密功能  Win11怎么开启自动HDR画质_Windows11显示设置HDR选项  Laravel安装步骤详细教程_Laravel环境搭建指南  Laravel如何将应用部署到生产服务器_Laravel生产环境部署流程  实例解析Array和String方法  如何用已有域名快速搭建网站?  如何快速生成ASP一键建站模板并优化安全性?  Laravel PHP版本要求一览_Laravel各版本环境要求对照  如何用景安虚拟主机手机版绑定域名建站?  Laravel怎么导出Excel文件_Laravel Excel插件使用教程  Claude怎样写约束型提示词_Claude约束提示词写法【教程】  Laravel观察者模式如何使用_Laravel Model Observer配置  详解ASP.NET 生成二维码实例(采用ThoughtWorks.QRCode和QrCode.Net两种方式)  Win11怎么关闭透明效果_Windows11辅助功能视觉效果设置  夸克浏览器网页跳转延迟怎么办 夸克浏览器跳转优化  如何快速使用云服务器搭建个人网站?  php8.4header发送头信息失败怎么办_php8.4header函数问题解决【解答】  浅析上传头像示例及其注意事项  如何制作新型网站程序文件,新型止水鱼鳞网要拆除吗?