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源码》

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

『运维备忘录』之 Ansible 自动化运维工具

一、简介 Ansible是基于Python开发&#xff0c;集合了众多运维工具&#xff08;puppet、cfengine、chef、func、fabric&#xff09;的优点&#xff0c;实现了批量系统配置、批量程序部署、批量运行命令等功能的自动化运维工具&#xff0c;广泛用于配置管理、应用部署以及任务协…

ArcGIS学习(六)地理数据库

ArcGIS学习(六)地理数据库 上个任务我们讲了一个非常重要的知识点一一坐标系。这个任务我们带来另外一个很重要的知识点一一地理数据库。 地理数据库的内容相比于坐标系简单很多! 首先,先让我们来学习下地理数据库的理论。 ArcGIS 中的地理数据库(Geodatabase)是一个用…

牛客网SQL264:查询每个日期新用户的次日留存率

官网链接&#xff1a; 牛客每个人最近的登录日期(五)_牛客题霸_牛客网牛客每天有很多人登录&#xff0c;请你统计一下牛客每个日期新用户的次日留存率。 有一个登录(login。题目来自【牛客题霸】https://www.nowcoder.com/practice/ea0c56cd700344b590182aad03cc61b8?tpId82 …

25、数据结构/二叉树相关练习20240207

一、二叉树相关练习 请编程实现二叉树的操作 1.二叉树的创建 2.二叉树的先序遍历 3.二叉树的中序遍历 4.二叉树的后序遍历 5.二叉树各个节点度的个数 6.二叉树的深度 代码&#xff1a; #include<stdlib.h> #include<string.h> #include<stdio.h> ty…

如何修复Mac的“ kernel_task” CPU使用率过高的Bug?

当计算机开始缓慢运行时&#xff0c;这从来都不是一件有趣的事情&#xff0c;但是当您弄不清它为何如此缓慢时&#xff0c;甚至会变得更糟。如果您已经关闭了所有程序&#xff0c;并且Mac上的所有内容仍然感觉像是在糖蜜中移动&#xff0c;这可能是令人讨厌的kernel_task导致高…

mysql 中文编码问题

前言 最近在学springboot整合mybatisplus技术&#xff0c;用到mysql数据库&#xff0c;然后发现在windows下插入数据表会出现中文乱码现象 (例如 “我是谁” 在数据库中就成了 “???”) windows show variables like %char%;建表时, 设置默认charset为gbk create table u…

3.1-媒资管理之需求分析+搭建Nacos

文章目录 媒资管理模块1 模块需求分析1.1 模块介绍1.2 业务流程1.2.1 上传图片1.2.2 上传视频1.2.3 处理视频1.2.4 审核媒资 2.2 搭建Nacos2.2.1 服务发现中心2.2.2 配置中心2.2.2.1 配置三要素2.2.2.3配置content-api 2.2.3 公用配置2.2.4 配置优先级2.2.5 导入配置文件2.2.6 …

【芯片设计- RTL 数字逻辑设计入门 11 -- 移位运算与乘法】

请阅读【嵌入式开发学习必备专栏 】 文章目录 移位运算与乘法Verilog Codeverilog 拼接运算符&#xff08;{}&#xff09;Testbench CodeVCS 波形仿真 问题小结 移位运算与乘法 已知d为一个8位数&#xff0c;请在每个时钟周期分别输出该数乘1/3/7/8,并输出一个信号通知此时刻输…

15章-Python编程:从入门到实践

第15章生成数据 数据可视化指的是通过可视化表示来探索数据&#xff0c;它与数据挖掘数紧密相关&#xff0c;而数据挖掘指的是使用代码来探索数据集的规律和关联。 数据集可以是用一行代码就能表示的小型数字列表&#xff0c;也可以是数以吉字节的数据。漂亮地呈现数据关乎的并…

Android Studio安装过程遇到SDK无法安装问题解决

首次打开studio遇到该类问题&#xff0c;需要下载SDK文件&#xff0c;后又发现SDK由于是Google源&#xff0c;无法进行正常安装&#xff0c;故转而进行SDK的镜像安装。 一、下载SDK Tools 地址&#xff1a;AndroidDevTools - Android开发工具 Android SDK下载 Android Studio…

Docker实战01

七十八、compse是什么能干嘛 docker-compose容器编排&#xff08;你的容器实例太多了&#xff0c;你如何管理&#xff0c;容器之间涉及到启动的顺序&#xff0c;容器之间涉及到网络通信的调用&#xff09; 1、是什么&#xff1f; Docker-Compose是Docker官方的开源项目&…

【Boost】:http_server模块(六)

http_server模块 一.安装cpp-httplib库二.基本使用服务器 一.安装cpp-httplib库 可以自己写一个http服务器&#xff0c;但比较麻烦&#xff0c;这里直接使用库。 在gitee上搜索cpp-httplib&#xff0c;任意找一个即可&#xff08;建议使用0.7.15版本&#xff09;。例如&#xf…

Qt QVariant类应用

QVariant类 QVariant类本质为C联合(Union)数据类型&#xff0c;它可以保存很多Qt类型的值&#xff0c;包括 QBrush&#xff0c;QColor&#xff0c;QString等等&#xff0c;也能存放Qt的容器类型的值。 QVariant::StringList 是 Qt 定义的一个 QVariant::type 枚举类型的变量&…

Java Stram 流对于返回对象的处理 (结束流)

Java Stram 流对于返回对象的处理 &#xff08;结束流&#xff09; package com.zhong.streamdemo.showdownstreamdemo;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;import java.util.*; import java.util.stream.Collectors; im…

移动应用开发Android 创建第一个Android项目

文章目录 一、创建第一个Android项目1.1 准备好Android Studio1.2 运行程序1.3 程序结构是什么app下的结构res - 子目录&#xff08;所有图片、布局、字AndroidManifest.xml 有四大组件&#xff0c;程序添加权限声明 Project下的结构 二、开发android时&#xff0c;部分库下载异…

Jetpack Compose之进度条介绍(ProgressIndicator)

JetPack Compose系列&#xff08;12&#xff09;—进度条介绍 Compose自带进度条控件有两个&#xff0c;分别是&#xff1a;CircularProgressIndicator&#xff08;圆形进度条&#xff09;和LinearProgressIndicator&#xff08;线性进度条&#xff09;。 CircularProgressIn…

Visual Studio 2010+C#实现信源编码

1. 要求 本文设计了一套界面系统&#xff0c;该系统能够实现以下功能&#xff1a; 克劳夫特不等式的计算&#xff0c;并且能够根据计算结果给出相应的信息。可通过用户输入的初始条件然后给出哈夫曼编码以及LZ编码&#xff0c;结果均通过对话框来显示哈夫曼编码结果包含相应的…

[word] word中怎么插入另外一个word文档 #媒体#职场发展

word中怎么插入另外一个word文档 word中怎么插入另外一个word文档&#xff1f;有有些小伙伴在制作文档的时候&#xff0c;可能需要用到多个文档进行配合制作&#xff0c;今天小Q来给大家演示一下&#xff0c;插入Word文档的方法&#xff0c;插入其他类型文档的方法也是一样的。…

【lesson44】进程间通信之匿名管道

文章目录 理解进程通信管道理解使用管道1.创建管道2.fork创建子进程3.构建单向通信信道子进程构建通信父进程构建通信 使用管道的完整版代码扩展Task.hppProcessPool.cc 理解进程通信 进程运行具有独立性—>进程想通信&#xff0c;难度其实是比较大的---->进程通信的本质…

PCA与梯度上升法

PAC 主成分分析&#xff08;Principal Component Analysis&#xff09; 一个非监督的机器学习算法主要用于数据的降维通过降维&#xff0c;可以发现更便于人类理解的特征其他应用&#xff1a;可视化&#xff1b;去噪 如何找到这个让样本间间距最大的轴&#xff1f; 如何定义样…