C# 表达式树Lambda扩展(四)
一、前言
本来计算这篇文章在后面需要运用的时候写的,但是既然写到表达式的扩展呢,就一起写完吧。
看到这个标题就有一种疑问,Lambda表达式本来就是表达式树,还需要怎么扩展?那就看看下面的内容,你就知道了。
表达式系列目录
C# 表达式树Lambda扩展(四)
二、Lambda扩展
这里先不忙解答上面的问题,我们先看下这样一个应用场景。
一个页面的请求,里面带有一些条件查询,请求类如下
- public class ScoreRequest
- {
- public string CourseName { get; set; }
- public string StudentName { get; set; }
- }
要求查询与课程名称和学生名称匹配的数据
数据源我们就以上一例子的数据源
数据源类
- public class ScoreClass
- {
- public string CourseName { get; set; }
- public string StudentName { get; set; }
- public decimal Score { get; set; }
- }
添加数据
- var datas = new List<ScoreClass>();
- datas.Add(new ScoreClass
- {
- CourseName = "数学",
- StudentName = "学生A",
- Score = 60
- });
- datas.Add(new ScoreClass
- {
- CourseName = "数学",
- StudentName = "学生B",
- Score = 65
- });
- datas.Add(new ScoreClass
- {
- CourseName = "数学",
- StudentName = "学生C",
- Score = 70
- });
- datas.Add(new ScoreClass
- {
- CourseName = "数学",
- StudentName = "学生D",
- Score = 75
- });
- datas.Add(new ScoreClass
- {
- CourseName = "数学",
- StudentName = "学生E",
- Score = 80
- });
- datas.Add(new ScoreClass
- {
- CourseName = "数学",
- StudentName = "学生F",
- Score = 81
- });
- datas.Add(new ScoreClass
- {
- CourseName = "数学",
- StudentName = "学生G",
- Score = 82
- });
- datas.Add(new ScoreClass
- {
- CourseName = "数学",
- StudentName = "学生H",
- Score = 83
- });
- datas.Add(new ScoreClass
- {
- CourseName = "数学",
- StudentName = "学生I",
- Score = 84
- });
好了现在我们就查询数据
- var request = new ScoreRequest()
- {
- CourseName = "数",
- StudentName = "H"
- };
- var resultDatas = datas.Where(e => e.CourseName.Contains(request.CourseName) && e.StudentName.Contains(request.StudentName))
- .ToList();
如果查询对象里面CourseName和StudentName字段都有值得话,这样写没问题。如果没值,那就最后的数据,就不准确了。
如果是直接拼凑sql语句,我们可以用if(String.IsNullOrEmpty())来判断,但是现在判断了,怎么拼凑Lambda表达式呢?
所以就需要我们对Lambda表达式进行扩展,让他支持这种情况。那上面的问题,就不用再专门回答了吧!!!!
创建一个LambdaExtension的类,代码如下
- public static class LambdaExtension
- {
- public static Expression<Func<T, bool>> True<T>() { return param => true; }
- public static Expression<Func<T, bool>> False<T>() { return param => false; }
- public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
- {
- return first.Compose(second, Expression.AndAlso);
- }
- public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
- {
- return first.Compose(second, Expression.OrElse);
- }
- private static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
- {
- var map = first.Parameters
- .Select((f, i) => new { f, s = second.Parameters[i] })
- .ToDictionary(p => p.s, p => p.f);
- var secondBody = PFTParameterExtension.ReplaceParameters(map, second.Body);
- return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
- }
- private class PFTParameterExtension : ExpressionVisitor
- {
- private readonly Dictionary<ParameterExpression, ParameterExpression> map;
- public PFTParameterExtension()
- {
- }
- public PFTParameterExtension(Dictionary<ParameterExpression, ParameterExpression> map)
- {
- this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
- }
- /// <summary>
- /// 替换参数
- /// </summary>
- /// <param name="map">The map.</param>
- /// <param name="exp">The exp.</param>
- /// <returns>Expression</returns>
- public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
- {
- return new PFTParameterExtension(map).Visit(exp);
- }
- protected override Expression VisitParameter(ParameterExpression p)
- {
- ParameterExpression replacement;
- if (map != null && map.Count > 0 && map.TryGetValue(p, out replacement))
- {
- p = replacement;
- }
- return base.VisitParameter(p);
- }
- }
- }
这里面私有化了一个表达式树访问器,他的作用主要是用来同步Lambda表达式里面的参数。
下面是调用方式
- var expression = LambdaExtension.True<ScoreClass>();
- if (!string.IsNullOrWhiteSpace(request.CourseName))
- expression = expression.And(e => e.CourseName.Contains(request.CourseName));
- if (!string.IsNullOrWhiteSpace(request.StudentName))
- expression = expression.And(et => et.StudentName.Contains(request.StudentName));
- var resultDatas = datas.Where(expression.Compile())
- .ToList();
- Console.WriteLine($"查询结果:\n{string.Join("\n", resultDatas.Select(e => $"{e.StudentName} {e.CourseName} {e.Score}"))}");
where条件里面只能带委托,而我们的expression是Lambda表达式,所以需要Compile进行委托编译。
运行结果:
仔细看代码,第一个条件And里面的参数是“e”,第二个条件里面的参数是et,同一个Lambda表达式里面(这里只有一个参数),参数肯定是一致的,所以在LambdaExtension类中,在合并两个Lambda表达式的时候,就需要将参数合并成一个。
经过这样的扩展,我们就可以根据我们的实际情况,拼凑好需要的表达式,得到我们想要的结果。
三、总结
表达式树方面的讲解,终于可以告一段落了。一直后没有这样的写文章,现在觉得写文章还是真的挺累的,今年中秋节的这三天,算是全部的给博客园了。不过这三天讲解的内容,基本上把后面Dapper的扩展需要用的技术都铺垫了,后面我们就继续对ORM的讲解了。其实没写一篇博文,蜗牛都会去罗列和梳理相关知识点,这也让蜗牛获益匪浅,也希望蜗牛的博客能帮助到园友,这就是所谓的“赠人玫瑰,手留余香”吧。
C# 表达式树Lambda扩展(四)的更多相关文章
- C# 表达式树分页扩展(三)
一.前言 前面我们知道了表达树的基本知识,也明白了怎么遍历和修改一个表达式,这里我们就一个实际的场景来进行功能开发. 表达式系列目录 C# 表达式树讲解(一) C# 表达式树遍历(二) C# 表达式树 ...
- C# 表达式树讲解(一)
一.前言 一直想写一篇Dpper的定制化扩展的文章,但是里面会设计到对Lambda表达式的解析,而解析Lambda表达式,就必须要知道表达式树的相关知识点.我希望能通过对各个模块的知识点或者运用能够多 ...
- C# 表达式树遍历(二)
一.前言 上一篇我们对表达式树有了初步的认识,这里我们将对表达式树进行遍历,只有弄清楚了他的运行原理,我们才可以对他进行定制化修改. 表达式系列目录 C# 表达式树讲解(一) C# 表达式树遍历(二) ...
- C#复习笔记(4)--C#3:革新写代码的方式(Lambda表达式和表达式树)
Lambda表达式和表达式树 先放一张委托转换的进化图 看一看到lambda简化了委托的使用. lambda可以隐式的转换成委托或者表达式树.转换成委托的话如下面的代码: Func<string ...
- C#中的Lambda表达式和表达式树
在C# 2.0中,通过方法组转换和匿名方法,使委托的实现得到了极大的简化.但是,匿名方法仍然有些臃肿,而且当代码中充满了匿名方法的时候,可读性可能就会受到影响.C# 3.0中出现的Lambda表达式在 ...
- Lambda表达式和表达式树
在C# 2.0中,通过方法组转换和匿名方法,使委托的实现得到了极大的简化.但是,匿名方法仍然有些臃肿,而且当代码中充满了匿名方法的时候,可读性可能就会受到影响.C# 3.0中出现的Lambda表达式在 ...
- Lambda表达式和Lambda表达式树
LINQ的基本功能就是创建操作管道,以及这些操作需要的任何状态. 为了富有效率的使用数据库和其他查询引擎,我们需要一种不同的方式表示管道中的各个操作.即把代码当作可在编程中进行检查的数据. Lambd ...
- Lambda表达式树
1.常量表达式树 Func< + ); 使用表达式树的方式 ConstantExpression a = Expression.Constant(); ConstantExpression b ...
- LinQ实战学习笔记(三) 序列,查询操作符,查询表达式,表达式树
序列 延迟查询执行 查询操作符 查询表达式 表达式树 (一) 序列 先上一段代码, 这段代码使用扩展方法实现下面的要求: 取进程列表,进行过滤(取大于10M的进程) 列表进行排序(按内存占用) 只保留 ...
随机推荐
- JVM总结(二)
JVM总结(2)java内存区域.字节码执行引擎 1.内存区域 程序计数器:知道线程执行位置,保证线程切换后能恢复到正确的执行位置. 虚拟机栈:存栈帧.栈帧里存局部变量表.操作栈.动态连接.方法返回地 ...
- GIS历史概述与WebGis应用开发技术浅解
声明:本篇在李晓晖的<杂谈WebGIS>,补充更多的资料说明.基于地图二次开发一直断断续续在做,这里算是补充一下基本功把.其实对于前端,WebGis开发都是api,抄demo,改.GIS深 ...
- 弹性盒子---CSS3布局方式
1.弹性盒子/伸缩盒子 如果要使用弹性盒子属性,首先要将父级元素变成弹性盒子 Flex-direction 设置伸缩盒子的内部元素的排列方式 Row 从左到右安行排列 Column 从上到下按 ...
- 以股票案例入门基于SVM的机器学习
SVM是Support Vector Machine的缩写,中文叫支持向量机,通过它可以对样本数据进行分类.以股票为例,SVM能根据若干特征样本数据,把待预测的目标结果划分成“涨”和”跌”两种,从而实 ...
- 某团面试题:JVM 堆内存溢出后,其他线程是否可继续工作?
转载注明:http://dwz.win/gHc 最近网上出现一个美团面试题:"一个线程OOM后,其他线程还能运行吗?".我看网上出现了很多不靠谱的答案.这道题其实很有难度,涉及的知 ...
- case when多条件
SELECT label ,label3 ,lon_cen ,lat_cen ,lon3 ,lat3 ,antenna_height ,horizontal_angle ,CASE WHEN roun ...
- 如何在不到12天的时间里将网站权重优化到1(纯白帽SEO方法)
之前操作了一个IDC网站,不到1个月的时间把网站的权重从0做到了1,本来想写篇文章分享相关的操作经验.后来因为网站整体规划的原因,IDC网站需要关闭一段时间做备案的更新,排名肯定就会掉了,然后怕大家看 ...
- JavaScript在web自动化测试中的作用
前言 JS的全称JavaScript,是一种运行在浏览器中的解释型脚本语言,通常用来实现web前端页面的基本功能,对于前端开发人员是不得不掌握的一门基本技能,但是对于做web自动化测试的人员来说,如果 ...
- freemarker导出复杂样式的Excel
freemarker导出复杂样式的Excel 代码地址: gitee https://gitee.com/suveng/demo/tree/master/chapter.002 代码存放于demo下面 ...
- Java 集合源码分析(一)HashMap
目录 Java 集合源码分析(一)HashMap 1. 概要 2. JDK 7 的 HashMap 3. JDK 1.8 的 HashMap 4. Hashtable 5. JDK 1.7 的 Con ...