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 表达式或常规方法更为合适。希望这能帮助你理解表达式树的适用场景和优势!

如果你有其他问题或需要进一步的帮助,请随时告诉我。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/84368.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络备忘录

计算机网络 - 网络互联与互联网 计算机网络重点学习本章&#xff0c;属于核心知识 包含网络层和传输层 的 相关协议 计算机网络层次重点掌握网络层与传输层。其中网络层主要是IP协议&#xff0c;解决主机-主机通信&#xff0c;传输层主要是TCP/UDP 协议&#xff0c;解决应用-…

跨界破局者鲁力:用思辨与创新重塑汽车流通行业标杆

来源&#xff1a;投资家 在汽车流通行业深度变革的浪潮中&#xff0c;东莞东风南方汽车销售服务有限公司塘厦分公司总经理鲁力历经近二十年行业深耕&#xff0c;构建了一条从汽车销售顾问到区域运营掌舵者的进阶范本。作为东风日产体系内兼具理论建构与实战穿透力的标杆管理者…

玄机-日志分析-IIS日志分析

1.phpstudy-2018站点日志.(.log文件)所在路径&#xff0c;提供绝对路径 2.系统web日志中状态码为200请求的数量是多少 3.系统web日志中出现了多少种请求方法 4.存在文件上传漏洞的路径是什么(flag{/xxxxx/xxxxx/xxxxxx.xxx} 5.攻击者上传并且利用成功的webshell的文件名是什…

微信小程序开发知识点

1. 微信小程序开发知识点 1.1. 公共引用 1.1.1. 公共 wxss 在app.wxss文件下写入组件样式&#xff0c;也可使用import方式应用单独公共样式&#xff0c;避免了每个页面单独引用。 import "./public/wxss/base.wxss";1.1.2. 公共组件 在app.json文件下写入组件&…

安卓基础(编译.Class)

方法安全性维护性开源友好度删除.java用.class❌ 极低❌ 差❌代码混淆 (ProGuard)✅ 中等✅ 易✅AAR 库模块✅ 高✅ 易✅ 对于.class 步骤 1&#xff1a;编译生成 .class 文件 ​​打开终端​​&#xff08;Android Studio 底部的 Terminal 标签页&#xff09; 导航到你的模块…

golang常用库之-go-feature-flag库(特性开关(Feature Flags))

文章目录 golang常用库之-go-feature-flag库&#xff08;特性开关&#xff08;Feature Flags&#xff09;&#xff09;一、什么是特性开关&#xff08;Feature Flags&#xff09;二、go-feature-flag库我可以使用 GO Feature Flag 做什么&#xff1f;选择使用 Open Feature SDK…

微前端 - Module Federation使用完整示例

Angular 框架中 项目结构 main-app/src/app/app.module.tsapp.component.ts micro-app/src/app/app.module.tsapp.component.ts主应用配置 安装必要依赖&#xff1a; ng add angular-architects/module-federation修改 webpack.config.js&#xff1a; const { share, Shar…

麒麟v10系统的docker重大问题解决-不支持容器名称解析

今天给客户在麒麟v10Kylin-Server-V10-SP1下安装nextcloudonlyoffice的时候出现无法连接onlyoffice的问题,经过分析找到了是docker版本过低的原因,现在把解决思路和步骤分享给大家。 一、问题 用一键安装工具,给客户装好了系统,Nextcloud可以正常访问 但是访问nextcloud中的o…

PyCharm中运行.py脚本程序

1.最近在弄一个python脚本程序&#xff0c;记录下运行过程。 2.编写的python程序如下 # # Copyright 2017 Pixar # # Licensed under the terms set forth in the LICENSE.txt file available at # https://openusd.org/license. # # Check whether this script is being run …

学习资料搜集-ARMv8 cache 操作

【ARM64】【cache/MMU】学习总结_arm64 mmu-CSDN博客 [mmu/cache]-ARMV8的cache的维护指令介绍_data cache set allocation-CSDN博客 https://download.csdn.net/blog/column/12036969/139483584 验证码_哔哩哔哩 【ARM Cache 与 MMU 系列文章 2 -- Cache Coherence及内存顺…

Flutter快速上手,入门教程

目录 一、参考文档 二、准备工作 下载Flutter SDK&#xff1a; 配置环境 解决环境报错 zsh:command not found:flutter 执行【flutter doctor】测试效果 安装Xcode IOS环境 需要安装brew&#xff0c;通过brew安装CocoaPods. 复制命令行&#xff0c;打开终端 分别执行…

八股文——JVM

1. JVM组成 1.1 JVM由哪些部分组成&#xff1f;运行流程&#xff1f; Java Virtual Machine&#xff1a;Java 虚拟机&#xff0c;Java程序的运行环境&#xff08;java二进制字节码的运行环境&#xff09;好处&#xff1a;一次编写&#xff0c;到处运行&#xff1b;自动内存管理…

在Pnetlab6上绕过TPM、安全启动和 RAM 检查安装windows 11笔记

笔者本次安装的windows11的镜像为: zh-cn_windows_11_enterprise_ltsc_2024_x64_dvd_cff9cd2d.iso 1、创建镜像目录并上传iso文件 mkdir /opt/unetlab/addons/qemu/win-win11x64-2024-LTSC //目录名称务必按照官方文档格式,否则无法识别 目录创建完成后,将.iso格式镜像上…

PCL点云库入门(第18讲)——PCL库点云特征之3DSC特征描述3D shape context descriptor

一、3DSC&#xff08;3D Shape Context&#xff09;特征算法原理 1. 背景 3DSC 是一种描述三维点云局部形状的特征描述子&#xff0c;受二维 Shape Context 的启发。它用于捕捉点云某一点局部的几何分布信息&#xff0c;对点云配准、识别等任务非常有效。 2. 基本思想 3DSC…

SpringBoot+Mysql校园跑腿服务平台系统源码

&#x1f497;博主介绍&#x1f497;&#xff1a;✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示&#xff1a;文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…

分库分表的取舍

文章目录 大数据量下采用**水平分表**的缺点**1. 跨表查询复杂性与性能下降****2. 数据分布不均衡****3. 分布式事务与一致性问题****4. 扩展性受限****5. 查询条件限制与索引管理复杂****6. 数据迁移与维护成本高****7. 业务逻辑复杂度增加****总结** shardingJdbc分片策略**1…

Vue3解决“找不到模块@/components/xxx.vue或其相应的类型声明ts文件(2307)”

问题 1&#xff1a;如果没有这个env.d.ts文件&#xff0c;就新建 declare module "*.vue" {import { DefineComponent } from "vue";const component: DefineComponent<{}, {}, any>;export default component; }2&#xff1a;如果有tsconfig.json文…

计算机视觉与深度学习 | 基于MATLAB的图像特征提取与匹配算法总结

基于MATLAB的图像特征提取与匹配算法全面指南 图像特征提取与匹配 基于MATLAB的图像特征提取与匹配算法全面指南一、图像特征提取基础特征类型分类二、点特征提取算法1. Harris角点检测2. SIFT (尺度不变特征变换)3. SURF (加速鲁棒特征)4. FAST角点检测5. ORB (Oriented FAST …

如何通过API接口获取淘宝商品列表?操作详解

一、准备工作 注册开发者账号 访问淘宝开放平台官网/万邦开放平台&#xff0c;完成企业开发者认证&#xff08;个人账号权限受限&#xff09;&#xff0c;使用已有淘宝账号可直接登录。创建应用并填写基本信息&#xff08;如应用名称、类型等&#xff09;&#xff0c;系统生成A…

大数据驱动企业决策智能化的路径与实践

&#x1f4dd;个人主页&#x1f339;&#xff1a;慌ZHANG-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 一、引言&#xff1a;数据驱动的企业竞争力重构 在这个瞬息万变的商业时代&#xff0c;“快者胜”的竞争逻辑愈发明显。企业如何在复杂环…