C#之表达式树使用

目的

遇到一个场景需要接收一个表的列来进行动态排序,比如我想根据CreateTime进行正序排序,加上我使用的ORM框架是EFCore,那么我一下子就想到应该使用OrderBy,然后接收一个要排序的列

query.OrderBy("CreateTime")

但是这样子是不行的,所以寻找方案后找到了一个nuget包System.Linq.Dynamic.Core,该包的用法如下

//OrderBy("time asc")
query.OrderBy($"{orderContent.SortName} {orderContent.Sort}");

但是把这样子就会多引用一个nuget包,所以就在继续找其他方法,就找到了使用表达式树来实现,那么就简单介绍几种表达式树可能用到的例子吧。

是什么

定义一种树状的数据结构来描述c#中的代码,这种树状的数据结构就是表达式树。

还是直接放上原文的链接吧

和委托的关系

表达式树其实与委托已经没什么关系了,非要扯上关系,那就这么说吧,表达式树是存放委托的容器。

要用Lambda表达式的时候,直接从表达式中获取出来,Compile()就可以直接用了。如下代码:

static void Main(string[] args)
{Expression<Func<int, int, int>> exp = (x, y) => x + y;Func<int, int, int> fun = exp.Compile();int result = fun(2, 3);
}

使用场景

平常我是很少或者几乎不自己构建表达式树,就像上面文章那个老哥说的那样子,表达式树一般是给框架的作者用的。

操作

下文中UserDto.GetUserDtos()返回的是一个UserDto集合(算是一个伪代码),虽然本文示例没有直接查询的数据库,但是我已经在其他项目中测试过,在执行输出SQL中已经体现出来效果。

本文示例虽已经过验证,但是还未上生产。

简单筛选

public void SampleWhere()
{var user = UserDto.GetUserDtos().AsQueryable();//泛型写法Func<UserDto, bool> predicate = s => s.Deleted=false;var list = user.Where(predicate).ToList(); // 这个执行是在内存中执行的//表达式树写法Expression<Func<UserDto, bool>> lambdaExp = (s) => !s.Deleted;var list2 = user.Where(lambdaExp).ToList();
}

通过简单的筛选去学习如何创建简单的表达式树

/// <summary>
/// 通过简单的筛选去学习
/// </summary>
public void SampleWhereToStudy()
{// 实现效果   t => t.Name == "张三"var user = UserDto.GetUserDtos().AsQueryable();var result1 = user.Where(t => t.Name == "张三");ParameterExpression demo = Expression.Parameter(typeof(UserDto), "t");Console.WriteLine(demo);MemberExpression demo_name = Expression.Property(demo, "Name");Console.WriteLine(demo_name);// t.NameConstantExpression value = Expression.Constant("张三");Console.WriteLine(value);// 张三BinaryExpression greaterThen = Expression.Equal(demo_name, value);Console.WriteLine(greaterThen); // t.Name=="张三"var lambda = Expression.Lambda<Func<UserDto, bool>>(greaterThen, demo);Console.WriteLine(lambda);// t=>t.Name=="张三"var lamdbaFunc = lambda.Compile();// 编译表达式Console.WriteLine(lamdbaFunc);// System.Func`2[CSharpBasic.Model.UserDto,System.Boolean]var resultTrue = lamdbaFunc(new UserDto { Name = "张三" });Console.WriteLine(resultTrue);//True// 筛选张三var result = user.Where(lamdbaFunc).ToList();
}

资料来自:超超老师教程

动态筛选

public void DynamicWhere()
{//实现效果:已知一个表UserDto  包含属性Name、Address、Id等,需要实现通过属性进行动态过滤var user = UserDto.GetUserDtos().AsQueryable();var list2 = user.EqualWhere("Name", "张三").FirstOrDefault();// 执行SQL:SELECT u.id, u.account,u.name FROM test."user" AS u WHERE u.name = '张三'
}// 扩展方法
public static class ExpressExtensons
{/// <summary>/// 等于筛选/// </summary>/// <typeparam name="T"></typeparam>/// <param name="queryable"></param>/// <param name="whereField"></param>/// <param name="value"></param>/// <returns></returns>public static IQueryable<T> EqualWhere<T>(this IQueryable<T> queryable, string whereField, object value){return queryable.Where<T>(whereField, value);}/// <summary>/// 小于筛选/// </summary>/// <typeparam name="T"></typeparam>/// <param name="queryable"></param>/// <param name="whereField"></param>/// <param name="value"></param>/// <returns></returns>public static IQueryable<T> LessWhere<T>(this IQueryable<T> queryable, string whereField, object value){return queryable.Where<T>(whereField, value, 1);}/// <summary>/// 大于筛选/// </summary>/// <typeparam name="T"></typeparam>/// <param name="queryable"></param>/// <param name="whereField"></param>/// <param name="value"></param>/// <returns></returns>public static IQueryable<T> GreaterWhere<T>(this IQueryable<T> queryable, string whereField, object value){return queryable.Where<T>(whereField, value, 1);}private static IQueryable<T> Where<T>(this IQueryable<T> queryable, string whereField, object value, int type = 0){var paramExp = Expression.Parameter(typeof(T), "t");//因为这个Property里面已经包含属性校验的功能,所以不用再另外写了var memberExp = Expression.Property(paramExp, whereField);//值表达式var valueExp = Expression.Constant(value);var exp = type switch{//小于1 => Expression.LessThan(memberExp, valueExp),//小于等于2 => Expression.LessThanOrEqual(memberExp, valueExp),//大于3 => Expression.GreaterThan(memberExp, valueExp),//大于等于4 => Expression.GreaterThanOrEqual(memberExp, valueExp),//等于_ => Expression.Equal(memberExp, valueExp),};var lambda = Expression.Lambda<Func<T, bool>>(exp, paramExp);return queryable.Where(lambda);}
}

动态排序

public void DynamicOrderby()
{// 实现效果var userQueryable = UserDto.GetUserDtos().AsQueryable();var sortList = userQueryable.OrderBy(t => t.CreateTime).ToList();foreach (var item in sortList){Console.WriteLine(item.CreateTime);}Console.WriteLine("-----------------");// 通过表达式树去实现效果var list = userQueryable.OrderBy("CreateTime", false);// 执行SQL:SELECT u.id, u.account, u.create_time FROM test."user" AS u ORDER BY u.create_time DESCforeach (var item in list){Console.WriteLine(item.CreateTime);}
}public static class ExpressExtensons
{/// <summary>/// 根据字段排序处理/// </summary>/// <typeparam name="T">泛型列</typeparam>/// <param name="queryable">查询queryable</param>/// <param name="sortField">排序列</param>/// <param name="isAsc">true正序 false倒序</param>/// <returns></returns>public static IQueryable<T> OrderBy<T>(this IQueryable<T> queryable, string sortField, bool isAsc = true){var parameter = Expression.Parameter(typeof(T));var property = typeof(T).GetProperty(sortField);if (property == null)throw new ArgumentNullException($"无效的属性 {sortField}");var memberExpression = Expression.Property(parameter, property);var orderbeExpression = Expression.Lambda(memberExpression, new ParameterExpression[] { parameter });var orderMethod = isAsc ? "OrderBy" : "OrderByDescending";var resultExpression = Expression.Call(typeof(Queryable), orderMethod, new Type[] { queryable.ElementType, property.PropertyType },new Expression[] { queryable.Expression, Expression.Quote(orderbeExpression) });return queryable.Provider.CreateQuery<T>(resultExpression);}
}

动态查询指定属性

通过传递一个字符串,然后查询指定的列返回

var userQueryable = UserDto.GetUserDtos().AsQueryable();ParameterExpression parameter1 = Expression.Parameter(typeof(UserDto));
MemberExpression men = Expression.Property(parameter1, "Name");
var selectFieldExpression = Expression.Lambda<Func<UserDto, string>>(men, new ParameterExpression[] { parameter1 });
var result1 = userQueryable.Select(selectFieldExpression).ToList();

通过编写一个映射后的类实现简单的对应映射转换

public void DynamicSelect()
{var userQueryable = UserDto.GetUserDtos().AsQueryable();// 简单映射转换var result2 = userQueryable.SelectMapper<UserDto, UserTest>().ToList();// 执行SQL:SELECT u.id AS "Id", u.account AS "Account" FROM test."user" AS u
}public static class ExpressExtensons
{/// <summary>/// 查询映射/// </summary>/// <typeparam name="T"></typeparam>/// <typeparam name="M"></typeparam>/// <param name="queryable"></param>/// <returns></returns>public static IQueryable<M> SelectMapper<T, M>(this IQueryable<T> queryable){var parameter = Expression.Parameter(typeof(T), "t");var newExpression = Expression.New(typeof(M));var mapperType = typeof(T).GetProperties();var listBinding = new List<MemberBinding>();foreach (var item in typeof(M).GetProperties()){if (!mapperType.Any(t => t.Name == item.Name)){continue;}var mem = Expression.Property(parameter, item.Name);// t.namevar member = typeof(M).GetMember(item.Name)[0];MemberBinding memBinding = Expression.Bind(member, mem);// 这里传mem是用t.name给他赋值listBinding.Add(memBinding);}var memberExp = Expression.MemberInit(newExpression, listBinding);var selectExpression = Expression.Lambda<Func<T, M>>(memberExp, new ParameterExpression[] { parameter });return queryable.Select(selectExpression);}
}

资料

表达式树资料:https://www.cnblogs.com/li-peng/p/3154381.html

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

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

相关文章

实现一个基于相等性比较的 GroupBy

实现一个基于相等性比较的 GroupByIntro在我们的系统里有些数据可能会有问题&#xff0c;数据源头不在我们这里&#xff0c;数据不好修复&#xff0c;在做 GroupBy 的时候就会很痛苦&#xff0c;默认的 group by 会依赖于 HashCode &#xff0c;而某些场景下 HashCode 可能并不…

win7系统下载 ghost win7 Sp1 64位纯净3月版

win7系统下载 ghost win7 Sp1 64位纯净3月版 软件名称: Ghost Win7 Sp1 64位纯净3月版软件语言: 简体中文软件大小: 5.25大小: GB发布日期: 2017-03-21文件名称: ZJY_Ghost_win 7_X64_CJ201703.GHOM D 5: EB16DCD608A5CCFE34B58…

CrossPHP框架的常用操作

1. 在视图控制器中使用$this->res()方法来生成资源文件的绝对路径$this->res(css/style.css);生成的连接为http://youdomain.com/static/css/style.css2. 生成指定app名称的连接$this->appUrl()第一个参数为基础url, 第二个参数为app名称, 第三个参数为 控制器:方法 第…

WPF-07 Style之触发器

触发器能够在改变属性值的时候&#xff0c;根据值变化执行操作&#xff0c;在不需要创建一个新的控件的情况下&#xff0c;可以动态的改变控件的外观&#xff0c;当条件满足时&#xff0c;触发器可以改变任何属性的值&#xff0c;触发器通常定义在Style中&#xff0c;在窗体的根…

jdk自带常用命令行工具使用

转自&#xff1a;http://blog.csdn.net/winwill2012/article/details/46364923jps命令使用jps命令类似于Linux下的ps命令&#xff0c;用于列出当前正在运行的所有Java进程。基本用法直接运行不加任何参数就能列出所有java进程的pid和类的短名称。例如&#xff1a;常用参数-q参数…

crossphp框架中,在模板中加载其他模板

这里说我自己做的项目的应用场景 要求是用layui框架的layer组件,实现弹出层效果,用原声PHP无疑很容易做到,但是如果应用到crossphp框架流程就会非常麻烦 这里简单讲一下大致的步骤: 1. 在一个模板文件中应用layui的layer组件实现弹出框 index.tpl.php2. 从我们自己定义的路径上…

for(auto c:s)与for(auto c:s)

在c11标准下可以执行的特殊格式的for循环语句&#xff0c;区别在于引用类型可以改变原来的值 #include<iostream> using namespace std; int main() {string s("hello world");for(auto c:s)ct;cout<<s<<endl;//结果为hello worldfor(auto &c:…

MASA Framework的MinimalAPIs应用

在以前的MVC引用程序中&#xff0c;控制器是一个功能齐全的框架&#xff0c;但它偏重&#xff0c;因此在.Net6.0官方引入了MinimalAPIs&#xff0c;即最小API&#xff0c;与MVC相比&#xff0c;它足够的简洁&#xff0c;适合小型服务来使用&#xff0c;下面就让我们看看如何使用…

【转】Java开发必须要知道的知识体系

Java Java是一门超高人气编程语言&#xff0c;拥有跨平台、面向对象、泛型编程等特性。在TIOBE编程语言排行榜中&#xff0c;连续夺得第一宝座&#xff0c;而且国内各大知名互联网公司&#xff0c;后端开发首选语言&#xff1a;非Java莫属。今天只是梳理下Java知识体系&#xf…

CrossPHP--在我们用ajax,js取不到指定数据时,我们可以换一种方式

项目中遇到的问题: 需求: 用的是layui的laypage组件,进行分页操作,熟悉layui的朋友都知道,laypage需要从服务端给其一个总条数, 但是在进行ajax请求时出了问题, 我是这样定义的但是调用的时候却无法将数值直接返回回去,所以这里只能更换一种思路 在控制器中进行数据的查询,然后…

VS 代码行数统计

按CTRLSHIFTF (Find in files)&#xff0c;勾上支持正则表达式&#xff0c;然后输入搜索内容&#xff1a; ^:b*[^:b#/].*$#开头和/开头或者空行都不计入代码量。如果需要只统计代码文件的代转载于:https://www.cnblogs.com/sunlyk/p/7484728.html

MySQL设置从库只读模式

常见现象 运维工作中会经常维护MySQL主从服务器&#xff0c;当然Slave我们只是用于读操作。 一般权限开通也只授权只读账号&#xff0c;但是有时候维护工作可能不是一个人在做&#xff0c;你不能保证其他同事都按照这个标准操作。 有同事可能会授权Slave库MySQL账号为all或者se…

寻找kernel32.dll的地址

为了寻找kernel32.dll的地址&#xff0c;可以直接输出&#xff0c;也可以通过TEB,PEB等查找。 寻找TEB: dt _TEB nt!_TEB 0x000 NtTib : _NT_TIB 0x01c EnvironmentPointer : Ptr32 Void 0x020 ClientId : _CLIENT_ID 0x028 ActiveRpcHandle : Ptr32 Void 0x02c ThreadLocalSto…

layui弹出层使用(layer.alert / layer.open / layer.prompt )

一 layer.alert 效果图: 代码: //取消提现 function back(id) {layer.alert(真的要取消吗, {skin: layui-layer-molv //样式类名 自定义样式,closeBtn: 1 // 是否显示关闭按钮,anim: 1 //动画类型,btn: [确定,取消] //按钮,icon: 6 // icon,yes:function(){return $.aj…

SkiaSharp 自绘弹幕效果

SkiaSharp 自绘弹幕效果控件名&#xff1a;SkiaSharpBarrage作者&#xff1a; 驚鏵原文链接&#xff1a; https://github.com/yanjinhuagood/SkiaSharpBarrage框架使用.NET60&#xff1b;Visual Studio 2022;项目使用 MIT 开源许可协议&#xff1b;接着上一篇 WPF 弹幕上期有…

JavaScript中this指向

一.重点来了&#xff0c;this指向问题&#xff1a;1.this指向之普通函数。 2.this指向之对象 3.this指向之构造函数 4.this指向之&#xff08;call,apply&#xff09;动态更改this指向。 二.具体分析如下 1.普通函数 // 第23行的调用者为null,this指向也为null,// 所以这时js把…

【python】python中的定义类属性和对像属性

python中变量是没有类型的可以绑定任意类型&#xff0c;但是在语法上不能声明变量。 那我们怎麽来声名一个变量呢&#xff1f; fNone 这样我们给着个变量绑定了以各None类型&#xff0c;我们随时可用重新绑定其它类型。这样我们起到了预先声名变量的效果。 类中如何去定义类的…

提交Form表单,submit之前做js判断处理

效果:在点击提交按钮时,首先进行js判断, 如果不符合条件,则alert出提示信息,并return false. 主要点就在于给form表单添加一个onsubmit事件. 在onsubmit事件中定义的函数里进行js验证处理.代码 : <!DOCTYPE html> <html lang"en"> <head><meta …

如何在Windows上一键部署PaddleOCR的WebAPI服务

PaddleOCR旨在打造一套丰富、领先、且实用的OCR工具库&#xff0c;助力开发者训练出更好的模型&#xff0c;并应用落地。官方开源项目地址&#xff1a;https://github.com/PaddlePaddle/PaddleOCR一定会有小伙伴们看完不知道如何部署与应用&#xff0c;怎么才能融入到自己的产品…

微软为 Visual Studio 扩展添加对 Arm64 的支持

微软在 6 月份推出了支持 Arm64 架构的 Visual Studio&#xff0c;这是第一个原生支持在基于 Arm 的处理器上构建和调试 Arm64 应用程序的 Visual Studio 版本。近日&#xff0c;他们宣布为 Visual Studio 扩展也添加了对 Arm64 的支持&#xff0c;因此开发者可在 Arm64 Visual…