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运行时数据区--深入理解Java虚拟机 读后感
程序计数器 程序计数器是线程私有的区域,很好理解嘛~,每个线程当然得有个计数器记录当前执行到那个指令.占用的内存空间小,可以把它看成是当前线程所执行的字节码的行号指示器.如果线程在执行Java方法,这 ...
- 把Python项目打包成exe文件
我们很多时候,写好的程序需要打包成.exe文件才可以发给客户,那么今天我就来谈一谈,如何将一个写好的Python程序打包成exe文件! 首先,我们我们使用到的工具是python 3.7 和 Pyins ...
- 压力测试-jmeter
1. 场景描述 新申请的服务器,要压测下python算法程序最多能执行多少条数据,有几年没用压力测试工具-jmeter了,重新下载了最新版本,记录下,也希望能帮到准备使用jmeter做压测的朋友. 2 ...
- JVM调优前戏之JDK命令行工具---jhat
在JDK的命令行中,一般开发人员最耳熟能详的肯定就是java,javac,javap等常用命令,不过在jdk/bin下还有许多其他的命令行工具,它们被用来监测JVM运行时的状态,下面我们来详细解读一下 ...
- JS实现循环删除数组中元素的方法介绍
这篇文章主要给大家介绍了关于Javascript循环删除数组中元素的几种方法,文中给出了详细的示例代码供大家参考学习,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧. 本文主要跟大家分享了 ...
- K8S搭建-1 Master 2 Workers(dashboard+ingress)
本文讲述k8s最新版的搭建(v1.15.2) 分如下几个topic步骤: 各个节点的基本配置 master节点的构建 worker节点的构建 安装dashboard 安装ingress 常见命令 do ...
- spring-boot-plus V1.2.1 发布 文件上传下载和静态资源访问
[V1.2.1-RELEASE] 2019.08.21 ⭐️ New Features 文件上传保存到服务器指定目录 文件下载 访问上传的图片等资源 启用项目静态资源访问,可访问static/temp ...
- Git安装与使用(windows环境)(一)----Git安装、生成公钥和私钥、添加SSH
安装 1.从官网下载git:http://git-scm.com/downloads 2.安装git,选择git组件安装,如下图 3.一直next,直到出现下面的窗口.这里是选择命令行形式.(可以理解 ...
- redux 源码阅读
目录 [目录结构] [utils] actionTypes.js isPlainObject.js warning.js [逻辑代码] index.js createStore.js compose. ...
- HTML连载33-背景定位
一.背景定位 同一个标签可以同时设置背景颜色和背景图片,如果颜色和图片同时存在,那么图片会覆盖颜色 1.在CSS中有一个叫做background-position:属性,就是专门用来控制背景图片的位置 ...