C#学习第29天:表达式树(Expression Trees)
目录
什么是表达式树?
核心概念
1.表达式树的构建
2. 表达式树与Lambda表达式
3.解析和访问表达式树
4.动态条件查询
表达式树的优势
1.动态构建查询
2.LINQ 提供程序支持:
3.性能优化
4.元数据处理
5.代码转换和重写
适用场景
代码复杂性的权衡
什么是表达式树?
- 表达式树是C#中一种数据结构,用于以树状方式表示代码中的表达式,每个节点代表一个操作(如算术运算、方法调用等)。
- 它们允许你将代码本身视为数据结构,能够在运行时动态地分析、修改和执行代码。
- 表达式树最初是在 .NET 3.5 中引入的,主要用于支持 LINQ(语言集成查询)。
核心概念
1.表达式树的构建
- 表达式树的核心类型位于 System.Linq.Expressions 命名空间。
- 可以手动构建表达式树,也可以通过Lambda表达式隐式构建。
using System;
using System.Linq.Expressions;class Program
{static void Main(){// 创建一个简单的表达式:x => x + 1ParameterExpression param = Expression.Parameter(typeof(int), "x");BinaryExpression body = Expression.Add(param, Expression.Constant(1));Expression<Func<int, int>> expression = Expression.Lambda<Func<int, int>>(body, param);// 编译并执行表达式树Func<int, int> compiledExpression = expression.Compile();int result = compiledExpression(5);Console.WriteLine($"Result: {result}"); // 输出:Result: 6}
}
在这个示例中,我们创建了一个简单的表达式树表示 x => x + 1,并将其编译成可执行代码。
2. 表达式树与Lambda表达式
Lambda表达式可以被编译为委托,也可以被表达式树捕获:
Expression<Func<int, int>> square = x => x * x;
此时,square不是一个委托,而是一棵描述 x * x 计算过程的树,可用于分析和转换。
3.解析和访问表达式树
表达式树可以遍历并分析其结构:
void PrintExpression(Expression exp, int level = 0)
{Console.WriteLine(new string(' ', level * 2) + exp.NodeType + " - " + exp.Type);if (exp is BinaryExpression bin){PrintExpression(bin.Left, level + 1);PrintExpression(bin.Right, level + 1);}else if (exp is ParameterExpression param){Console.WriteLine(new string(' ', (level+1) * 2) + "Parameter: " + param.Name);}
}
4.动态条件查询
我们有一个 Product 类和一个产品列表。我们希望根据产品的价格动态过滤产品。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;public class Product
{public string Name { get; set; }public decimal Price { get; set; }
}class Program
{static void Main(){// 创建产品列表List<Product> products = new List<Product>{new Product { Name = "Laptop", Price = 1000m },new Product { Name = "Smartphone", Price = 500m },new Product { Name = "Tablet", Price = 300m }};// 动态创建表达式树来过滤价格大于 400 的产品Func<Product, bool> filter = CreatePriceFilter(400m);// 使用生成的过滤器查询产品var filteredProducts = products.Where(filter).ToList();foreach (var product in filteredProducts){Console.WriteLine($"Product: {product.Name}, Price: {product.Price}");}}static Func<Product, bool> CreatePriceFilter(decimal minPrice){// 创建参数表达式ParameterExpression param = Expression.Parameter(typeof(Product), "product");// 创建访问属性表达式MemberExpression priceProperty = Expression.Property(param, "Price");// 创建常量表达式ConstantExpression constant = Expression.Constant(minPrice);// 创建大于运算符表达式BinaryExpression comparison = Expression.GreaterThan(priceProperty, constant);// 创建 lambda 表达式Expression<Func<Product, bool>> lambda = Expression.Lambda<Func<Product, bool>>(comparison, param);// 编译表达式树为可执行代码return lambda.Compile();}
}
1.设置产品列表:
- 我们先定义一个简单的 Product 类和一个包含几个产品的列表。
2.创建表达式树:
- 参数表达式:ParameterExpression param = Expression.Parameter(typeof(Product), "product"); 创建一个参数,表示传递给过滤器的 Product 对象。
- 属性访问表达式:MemberExpression priceProperty = Expression.Property(param, "Price"); 访问传递对象的 Price 属性。
- 常量表达式:ConstantExpression constant = Expression.Constant(minPrice); 定义过滤条件中的常量值。
- 比较表达式:BinaryExpression comparison = Expression.GreaterThan(priceProperty, constant); 创建一个比较表达式,检查 Price 是否大于 minPrice。
- lambda 表达式:将上述表达式组合成一个完整的 lambda 表达式,并编译成可执行代码。
3.应用表达式:
-
使用 Where 方法将生成的过滤器应用于产品列表,并输出结果。
表达式树的优势
1.动态构建查询
- 表达式树允许你在运行时构建和修改查询逻辑。这在需要根据用户输入或其他动态数据生成不同查询条件时特别有用。
2.LINQ 提供程序支持:
- 表达式树是 LINQ 提供程序(如 LINQ to SQL、Entity Framework)的基础,它们将表达式树解析为底层数据源(如数据库、XML)的查询语言。这意味着你可以用相同的代码生成运行在不同数据源上的查询。
3.性能优化
- 在某些情况下,表达式树可以被编译和缓存,提高重复执行相同逻辑的性能。
4.元数据处理
- 表达式树提供对表达式结构的访问,这使得分析和处理代码元数据成为可能。这对于开发动态应用程序或框架尤其有用。
5.代码转换和重写
- 可以编写代码来遍历和修改表达式树,用于实现代码转换或重写。这对于构建复杂查询或分析工具有很大帮助。
适用场景
- 动态条件查询:当应用需要支持用户定义的动态过滤条件时,表达式树可以灵活地构建这些条件。
- 跨平台查询:在 LINQ to SQL 或 Entity Framework 中,表达式树可被翻译成 SQL 查询,在数据库执行。
- 规则引擎和DSL(领域特定语言):在这些场景中,表达式树可以用于解析和执行用户定义的规则或查询
代码复杂性的权衡
- 虽然表达式树代码在某些情况下显得复杂,但其提供的灵活性和功能在复杂应用中是非常关键的。
- 如果只是简单的筛选条件,直接使用 Lambda 表达式或 LINQ 查询语法更为直接和清晰。
示例1:
假设我们有一个产品列表,用户可以动态选择多个条件进行过滤,比如根据名称、价格范围或库存状态等进行筛选。我们需要在运行时根据用户输入组合这些条件。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;public class Product
{public string Name { get; set; }public decimal Price { get; set; }public bool InStock { get; set; }
}class Program
{static void Main(){var products = new List<Product>{new Product { Name = "Laptop", Price = 1000, InStock = true },new Product { Name = "Smartphone", Price = 500, InStock = true },new Product { Name = "Tablet", Price = 300, InStock = false }};// 用户可以选择动态条件string searchName = "Laptop";decimal? minPrice = 400;decimal? maxPrice = null;bool? inStock = true;// 创建动态查询表达式var filter = CreateDynamicFilter<Product>(searchName, minPrice, maxPrice, inStock);// 使用生成的过滤器查询产品var filteredProducts = products.AsQueryable().Where(filter).ToList();foreach (var product in filteredProducts){Console.WriteLine($"Product: {product.Name}, Price: {product.Price}, InStock: {product.InStock}");}}static Expression<Func<T, bool>> CreateDynamicFilter<T>(string name, decimal? minPrice, decimal? maxPrice, bool? inStock){// 参数表达式var parameter = Expression.Parameter(typeof(T), "product");Expression expression = Expression.Constant(true); // 初始谓词为 true// 根据 name 动态创建条件if (!string.IsNullOrEmpty(name)){var nameProperty = Expression.Property(parameter, "Name");var nameValue = Expression.Constant(name);var nameExpression = Expression.Equal(nameProperty, nameValue);expression = Expression.AndAlso(expression, nameExpression);}// 根据 minPrice 创建条件if (minPrice.HasValue){var priceProperty = Expression.Property(parameter, "Price");var minPriceValue = Expression.Constant(minPrice.Value);var minPriceExpression = Expression.GreaterThanOrEqual(priceProperty, minPriceValue);expression = Expression.AndAlso(expression, minPriceExpression);}// 根据 maxPrice 创建条件if (maxPrice.HasValue){var priceProperty = Expression.Property(parameter, "Price");var maxPriceValue = Expression.Constant(maxPrice.Value);var maxPriceExpression = Expression.LessThanOrEqual(priceProperty, maxPriceValue);expression = Expression.AndAlso(expression, maxPriceExpression);}// 根据 inStock 创建条件if (inStock.HasValue){var stockProperty = Expression.Property(parameter, "InStock");var stockValue = Expression.Constant(inStock.Value);var stockExpression = Expression.Equal(stockProperty, stockValue);expression = Expression.AndAlso(expression, stockExpression);}// 创建 Lambda 表达式return Expression.Lambda<Func<T, bool>>(expression, parameter);}
}
示例2:
针对上文中只针对价格做筛选的示例,那么我们的筛选过程完全可以简化成如下表达式
var filteredProducts = products.Where(p => p.Price > 400).ToList();
总结来说,是否使用表达式树取决于你的具体需求和应用场景。在需要动态处理和复杂逻辑的情况下,表达式树提供了强大的工具支持,而在简单场景下,直接使用 Lambda 表达式或常规方法更为合适。希望这能帮助你理解表达式树的适用场景和优势!
如果你有其他问题或需要进一步的帮助,请随时告诉我。
相关文章:
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...

接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...

STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...

【JVM】Java虚拟机(二)——垃圾回收
目录 一、如何判断对象可以回收 (一)引用计数法 (二)可达性分析算法 二、垃圾回收算法 (一)标记清除 (二)标记整理 (三)复制 (四ÿ…...
快刀集(1): 一刀斩断视频片头广告
一刀流:用一个简单脚本,秒杀视频片头广告,还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农,平时写代码之余看看电影、补补片,是再正常不过的事。 电影嘛,要沉浸,…...

并发编程 - go版
1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...

免费数学几何作图web平台
光锐软件免费数学工具,maths,数学制图,数学作图,几何作图,几何,AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...

基于Springboot+Vue的办公管理系统
角色: 管理员、员工 技术: 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能: 该办公管理系统是一个综合性的企业内部管理平台,旨在提升企业运营效率和员工管理水…...

Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...

Razor编程中@Html的方法使用大全
文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...

Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...

iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...

Golang——6、指针和结构体
指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...

三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...

宇树科技,改名了!
提到国内具身智能和机器人领域的代表企业,那宇树科技(Unitree)必须名列其榜。 最近,宇树科技的一项新变动消息在业界引发了不少关注和讨论,即: 宇树向其合作伙伴发布了一封公司名称变更函称,因…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...

【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

uniapp 开发ios, xcode 提交app store connect 和 testflight内测
uniapp 中配置 配置manifest 文档:manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号:4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...
NPOI Excel用OLE对象的形式插入文件附件以及插入图片
static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...