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的进程) 列表进行排序(按内存占用) 只保留 ...
随机推荐
- python3学习-pickle模块
pickle提供了一个简单的持久化功能.可以将对象以文件的形式存放在磁盘上. 基本接口: pickle.dump(obj, file, [,protocol]) 注解:将对象obj保存到文件file中 ...
- postman->newman->jenkins构建过程的问题记录及解决方法
从postman导出请求集合后要做的工作: 需要调整导出的json文件,如配置环境变量{{host}},需要修改成准确的url; 通过newman执行newman run test_request.j ...
- SonarQube系列三、Jenkins集成SonarQube(dotnetcore篇)
[前言] 本系列主要讲述sonarqube的安装部署以及如何集成jenkins自动化分析.netcore项目.目录如下: SonarQube系列一.Linux安装与部署 SonarQube系列二.分析 ...
- 洛谷 P3648 [APIO2014]序列分割
题意简述 有一个长度为n的序列,分成k + 1非空的块, 选择两个相邻元素把这个块从中间分开,得到两个非空的块. 每次操作后你将获得那两个新产生的块的元素和的乘积的分数.求总得分最大值. 题解思路 f ...
- lxml解析网页
目录 1. 什么是lxml 2. 初次使用 3. xpath 3.2 标签定位 3.3 序列定位 3.4 轴定位 4. 实例 1. 什么是lxml lxml是干什么的?简单的说来,lxml是帮助我们解 ...
- 关于 .Net Core runtimeconfig 文件说明
在项目的bin\debug\netcoreapp${Version}下面能够找到这个${AppName}.runtimeconfig.json文件,简单来说,它就是用来定义用用程序所用的共享框架(.N ...
- Nginx+Zuul集群实现高可用网关
代码参考:https://github.com/HCJ-shadow/Zuul-Gateway-Cluster-Nginx Zuul的路由转发功能 前期准备 搭建Eureka服务注册中心 服务提供者m ...
- docker安装Ubuntu以及ssh连接
一.简述 环境: Windows10 docker:2.1.0.1 二.开始安装 Windows的docker安装就不再多说了,网上有很多教程 在docker的hub仓库中,有专门的ubuntu系统. ...
- 2019-在iOS里添加admob横幅广告示例
下载sdk , 解压 导入项目文件夹: 在info.plist里加入应用id(不是广告单元id): GADApplicationIdentifier 设置Build Settings选项 设置ap ...
- Liunx学习总结(二)--目录和文件管理
之前我们了解了什么是 liunx ,并且认识了它的目录结构,今天我们就来学习下如何进行目录和文件的管理. 创建目录 语法: mkdir [-mp] 目录名称 选项与参数 -m :配置文件的权限喔!直接 ...