c#: 表达式树的简化

环境:

  • .net 6

一、问题?

有下面的表达式:

var nums = new List<int> { 1, 2, 3 };
Expression<Func<int, bool>> exp = i => i > nums.Max();

我们知道,它其实就是:exp = i => i > 3;
那么问题是,我们如何将它改造成这样呢?

在orm解析lambda生成sql时,也经常遇到这样的窘境:

var scores = new List<Person> { new Person { Id = 1, Score = 60 } };
var sql = orm.Select<Person>().Where(i => i.Score > scores.Select(i=>i.Score).Max() || i.Score == 100).ToSql();
//error: 
// System.Exception:“未实现函数表达式 value(Program+<>c__DisplayClass0_0).scores.Select(i => i.Score).Max() 解析,如果正在操作导航属性集合,请使用 .AsSelect().Max()”


public class Person
{
    public int Id { get; set; }
    public double Score { get; set; }
}

所以,就有了个想法:能不能对表达式进行简化呢?
就比如上面的可以改造成:orm.Select<Person>().Where(i => i.Score > 60 || i.Score == 100).ToSql();

二、表达式树简化原理

lambda表达式是表达式树的根, 它可能会有参数列表, 其子孙节点可能会引用这些参数, 也可能没有引用, 将没有引用的分支编译求值, 将结果再“放回”表达式中即可!

还是以下面的表达式为例:

var nums = new List<int> { 1, 2, 3 };
Expression<Func<int, bool>> exp = i => i > nums.Max();

在节点 > 的右侧 nums.Max() 没有引用参数列表, 那么它就可以被简化, 简化后就是:
exp = i => i > 3;

再看如下:

var nums = new List<int> { 1, 2, 3 };
Expression<Func<int, bool>> expr = i => i > nums.Max() || nums.Count > 0;

我们不仅可以将 || 右侧的简化为 true, 还可以根据||的短路特性对整体进行简化, 结果如下:
exp = i => true

三、表达式树的树状图

我们知道有各种各样的表达式类型, 如: +-/*Call/MemberInit等。
无论哪种类型, 都可以将它们抽象成一棵树, 如:
Call类型的表达式, 可以看成:

在这里插入图片描述

表达式的嵌套:
lambda表达式有可能会嵌套lambda, 如:

var nums = new List<int> { 1, 2, 3 };
Expression<Func<int>> expr = () => Filter(nums, i => i > 1);

static int Filter(List<int> nums, Func<int, bool> func)
{
    return nums.First(i => func(i));
}

它的结构树如下:
在这里插入图片描述

这个是函数接受委托的, 还有函数接受lambda的,如:

var nums = new List<int> { 1, 2, 3 };
Expression<Func<int>> expr = () => Filter(nums, i => i > 1);
static int Filter(List<int> nums, Expression<Func<int, bool>> expression)
{
    return nums.First(i => expression.Compile()(i));
}

此时,它的结构树如下:
在这里插入图片描述

四、成品代码

在DotNetCommon.Core``已封装好了表达式树简化的方法,如下:
在这里插入图片描述
更多细节,参考:《DotNetCommon源码》

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

史上最全嵌入式(学习路线、应用开发、驱动开发、推荐书籍、软硬件基础)

废话不多说直接上思维导图&#xff01; 如果有觉得图片看不清楚的&#xff0c;有疑问的&#xff0c;可在评论区进行留言&#xff01; 群号&#xff1a; 228447240 嵌入式总括 嵌入式书籍推荐 嵌入式软件知识 嵌入式硬件知识 嵌入式应用开发 嵌入式驱动开发 嵌入式视频推荐: 韦…

5秒搭建PalWorld幻兽帕鲁游戏服务器,你信吗?

5秒搭建PalWorld幻兽帕鲁游戏服务器&#xff0c;你信吗&#xff1f;腾讯云推出幻兽帕鲁专属镜像系统&#xff0c;直接选择镜像&#xff0c;5秒搞定&#xff0c;全自动化部署。 幻兽帕鲁太火了&#xff0c;官方palworld服务器不稳定&#xff1f;不如自建服务器&#xff0c;基于…

双归同一运营商的 BGP 部署

一、拓朴如下&#xff1a; 要求&#xff1a; 1、AS100 只接收 AS200 和 300 的路由&#xff0c;不接收其它 AS 的明细路由&#xff1b; 2、对于 AS100 的业务流量出方向&#xff0c;所有到 AS200 和 300 的流量&#xff0c;优先选择 Line-1&#xff0c;而到 AS400 的流…

SpringBoot Security安全认证框架初始化流程认证流程之源码分析

SpringBoot Security安全认证框架初始化流程&认证流程之源码分析 以RuoYi-Vue前后端分离版本为例分析SpringBoot Security安全认证框架初始化流程&认证流程的源码分析 目录 SpringBoot Security安全认证框架初始化流程&认证流程之源码分析一、SpringBoot Security安…

5.electron之主进程起一个本地服务

如果可以实现记得点赞分享&#xff0c;谢谢老铁&#xff5e; Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 Electron 将 Chromium 和 Node.js 嵌入到了一个二进制文件中&#xff0c;因此它允许你仅需一个代码仓库&#xff0c;就可以撰写支持 Windows、…

基于SpringBoot和PostGIS的震中影响范围可视化实践

目录 前言 一、基础数据 1、地震基础信息 2、全国行政村 二、Java后台服务设计 1、实体类设计 2、Mapper类设计 3、控制器设计 三、前端展示 1、初始化图例 2、震中位置及影响范围标记 3、行政村点查询及标记 总结 前言 地震等自然灾害目前还是依然不能进行准确的预…

基于Springboot的足球社区管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的足球社区管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构…

8.0 Zookeeper 四字命令教程详解

zookeeper 支持某些特定的四字命令与其交互&#xff0c;用户获取 zookeeper 服务的当前状态及相关信息&#xff0c;用户在客户端可以通过 telenet 或者 nc&#xff08;netcat&#xff09; 向 zookeeper 提交相应的命令。 安装 nc 命令&#xff1a; $ yum install nc …

[office] Excel 2016怎么绘图?Excel2016绘图图文教程 #媒体#经验分享

Excel 2016怎么绘图&#xff1f;Excel2016绘图图文教程 这篇文章主要为大家介绍了Excel 2016怎么绘图&#xff1f;这篇文章主要介绍了Excel2016绘图图文教程 Excel作为数据处理分析软件&#xff0c;是非常好用的软件。里面可以进行数据统计与分析&#xff0c;如果要使得 Exce…

坚持刷题|二叉树的最近公共祖先

文章目录 题目考察点代码实现实现总结为什么不用迭代的方法实现&#xff1f;二叉搜索树的最近公共祖先 Hello&#xff0c;大家好&#xff0c;我是阿月。坚持刷题&#xff0c;老年痴呆追不上我&#xff0c;今天刷&#xff1a;二叉树的最近公共祖先 题目 236.二叉树的最近公共祖…

JavaWeb后端开发(第一期):Maven基础、Maven的安装配置、如何创建maven项目模块、maven的生命周期

Java后端开发&#xff1a;2024年2月6日 -> LiuJinTao 文章目录 JavaWeb后端开发&#xff08;第一期&#xff09; &#xff1a; maven基础一、 maven介绍1.1 什么maven呢&#xff1a;1.2 maven的作用1.3 maven 模型1.4 maven 仓库 二、maven 安装2.1 配置本地仓库2.2 配置阿里…

设计模式-行为型模式(下)

1.访问者模式 访问者模式在实际开发中使用的非常少,因为它比较难以实现并且应用该模式肯能会导致代码的可读性变差,可维护性变差,在没有特别必要的情况下,不建议使用访问者模式. 访问者模式(Visitor Pattern) 的原始定义是&#xff1a; 允许在运行时将一个或多个操作应用于一…

调和平均

L1-4 调和平均 分数 10 作者 陈越 单位 浙江大学 N 个正数的算数平均是这些数的和除以 N&#xff0c;它们的调和平均是它们倒数的算数平均的倒数。本题就请你计算给定的一系列正数的调和平均值。 输入格式&#xff1a…

Java学习-常用API(一)

Object类 Object类及其常用方法&#xff1a; 代码示例&#xff1a; Objects Objects类的引入&#xff0c;定义及其常见的方法&#xff1a; 示例 包装类 什么是包装类&#xff1f; 自动装箱和自动拆箱&#xff1a; 常用方法&#xff1a; 注意&#xff1a;字符串的 数值&#xf…

VS无法使用万能头文件#include <bits/stdc++.h> 的解决办法

第一步在vs中打出可以使用的头文件 如#include<cmath> 点击F12转到文档 上面窗口右键找到打开所在文件夹 创建一个名字为bits的文件夹 里面创建一个text文件 // C includes used for precompiling -*- C -*-// Copyright (C) 2003-2015 Free Software Foundation, In…

Java小区物业管理系统

技术架构&#xff1a; springboot mybatis thymeleaf Mysql5.7 有需要该项目的小伙伴可以私信我你的Q。 功能描述&#xff1a; 控制台、数据库、楼栋管理、单元管理、房屋管理、车位管理、缴费类型、缴费管理、公告管理、维修管理、投诉管理、用户管理 效果图&#xff…

ONLYOFFICE 文档开发者版 8.0:API和文档生成器更新

随着 8.0 版新功能的发布&#xff0c;我们更新了编辑器、文档生成器和插件的 API。请阅读本文了解详情。 PDF 支持 我们在 documentType 参数中添加了 pdf 文档这一类型。现在完全支持PDF文件*&#xff0c;包括含有可填写字段的文件&#xff0c;并且可以在ONLYOFFICE PDF 编辑…

Leetcode—134. 加油站【中等】

2024每日刷题&#xff08;113&#xff09; Leetcode—134. 加油站 实现代码 class Solution { public:int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {int gasSum accumulate(gas.begin(), gas.end(), 0);int costSum accumulate(cost…

【SpringBoot】application配置(5)

type-aliases-package: com.rabbiter.cm.domaintype-aliases-package: 这个配置用于指定mybatis的别名&#xff0c;别名是一个简化的方式&#xff0c;让你在Mapper xml 文件中引用java类型&#xff0c;而不需要使用使用完整的类名。例如&#xff0c;如果你在 com.rabbiter.cm.d…

C#调用WechatOCR.exe实现本地OCR文字识别

最近遇到一个需求&#xff1a;有大量的扫描件需要还原为可编辑的文本&#xff0c;很显然需要用到图片OCR识别为文字技术。本来以为这个技术很普遍的&#xff0c;结果用了几个开源库&#xff0c;效果不理想。后来&#xff0c;用了取巧的方法&#xff0c;直接使用了WX的OCR识别模…