马上加入IBC程序猿 各种源码随意下,各种教程随便看! 注册 每日签到 加入编程讨论群

C#教程 ASP.NET教程 C#视频教程程序源码享受不尽 C#技术求助 ASP.NET技术求助

【源码下载】 社群合作 申请版主 程序开发 【远程协助】 每天乐一乐 每日签到 【承接外包项目】 面试-葵花宝典下载

官方一群:

官方二群:

C# 表达式树Lambda扩展(四)

[复制链接]
查看1926 | 回复0 | 2019-9-17 11:33:39 | 显示全部楼层 |阅读模式

一、前言

原来盘算这篇文章在反面必要运用的时间写的,但是既然写到表达式的扩展呢,就一起写完吧。

看到这个标题就有一种疑问,Lambda表达式原来就是表达式树,还必要怎么扩展?那就看看下面的内容,你就知道了。

表达式系列目录

C# 表达式树讲解(一)

C# 表达式树遍历(二)

C# 表达式树分页扩展(三)

C# 表达式树Lambda扩展(四)

二、Lambda扩展

这里先不忙解答上面的题目,我们先看下这样一个应用场景。

一个页面的请求,内里带有一些条件查询,请求类如下

  1. public class ScoreRequest
  2. {
  3. public string CourseName { get; set; }
  4. public string StudentName { get; set; }
  5. }
复制代码

要求查询与课程名称和学生名称匹配的数据

数据源我们就以上一例子的数据源

数据源类

113354yratxqqh8i72qaqq.gif
113354t607z31ac6232368.gif
  1. public class ScoreClass
  2. {
  3. public string CourseName { get; set; }
  4. public string StudentName { get; set; }
  5. public decimal Score { get; set; }
  6. }
复制代码
View Code

添加数据

113354j3ym6wfeefy8hhyf.gif
113354d6nwtmq61p0gbauq.gif
  1. var datas = new List<ScoreClass>();
  2. datas.Add(new ScoreClass
  3. {
  4. CourseName = "数学",
  5. StudentName = "学生A",
  6. Score = 60
  7. });
  8. datas.Add(new ScoreClass
  9. {
  10. CourseName = "数学",
  11. StudentName = "学生B",
  12. Score = 65
  13. });
  14. datas.Add(new ScoreClass
  15. {
  16. CourseName = "数学",
  17. StudentName = "学生C",
  18. Score = 70
  19. });
  20. datas.Add(new ScoreClass
  21. {
  22. CourseName = "数学",
  23. StudentName = "学生D",
  24. Score = 75
  25. });
  26. datas.Add(new ScoreClass
  27. {
  28. CourseName = "数学",
  29. StudentName = "学生E",
  30. Score = 80
  31. });
  32. datas.Add(new ScoreClass
  33. {
  34. CourseName = "数学",
  35. StudentName = "学生F",
  36. Score = 81
  37. });
  38. datas.Add(new ScoreClass
  39. {
  40. CourseName = "数学",
  41. StudentName = "学生G",
  42. Score = 82
  43. });
  44. datas.Add(new ScoreClass
  45. {
  46. CourseName = "数学",
  47. StudentName = "学生H",
  48. Score = 83
  49. });
  50. datas.Add(new ScoreClass
  51. {
  52. CourseName = "数学",
  53. StudentName = "学生I",
  54. Score = 84
  55. });
复制代码
View Code

好了现在我们就查询数据

  1. var request = new ScoreRequest()
  2. {
  3. CourseName = "数",
  4. StudentName = "H"
  5. };
  6. var resultDatas = datas.Where(e => e.CourseName.Contains(request.CourseName) && e.StudentName.Contains(request.StudentName))
  7. .ToList();
复制代码

假如查询对象内里CourseName和StudentName字段都有值得话,这样写没题目。假如没值,那就最后的数据,就不正确了。

假如是直接拼凑sql语句,我们可以用if(String.IsNullOrEmpty())来判断,但是现在判断了,怎么拼凑Lambda表达式呢?

所以就必要我们对Lambda表达式进行扩展,让他支持这种情况。那上面的题目,就不用再专门答复了吧!!!!

创建一个LambdaExtension的类,代码如下

  1. public static class LambdaExtension
  2. {
  3. public static Expression<Func<T, bool>> True<T>() { return param => true; }
  4. public static Expression<Func<T, bool>> False<T>() { return param => false; }
  5. public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
  6. {
  7. return first.Compose(second, Expression.AndAlso);
  8. }
  9. public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
  10. {
  11. return first.Compose(second, Expression.OrElse);
  12. }
  13. private static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
  14. {
  15. var map = first.Parameters
  16. .Select((f, i) => new { f, s = second.Parameters[i] })
  17. .ToDictionary(p => p.s, p => p.f);
  18. var secondBody = PFTParameterExtension.ReplaceParameters(map, second.Body);
  19. return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
  20. }
  21. private class PFTParameterExtension : ExpressionVisitor
  22. {
  23. private readonly Dictionary<ParameterExpression, ParameterExpression> map;
  24. public PFTParameterExtension()
  25. {
  26. }
  27. public PFTParameterExtension(Dictionary<ParameterExpression, ParameterExpression> map)
  28. {
  29. this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
  30. }
  31. /// <summary>
  32. /// 替换参数
  33. /// </summary>
  34. /// <param name="map">The map.</param>
  35. /// <param name="exp">The exp.</param>
  36. /// <returns>Expression</returns>
  37. public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
  38. {
  39. return new PFTParameterExtension(map).Visit(exp);
  40. }
  41. protected override Expression VisitParameter(ParameterExpression p)
  42. {
  43. ParameterExpression replacement;
  44. if (map != null && map.Count > 0 && map.TryGetValue(p, out replacement))
  45. {
  46. p = replacement;
  47. }
  48. return base.VisitParameter(p);
  49. }
  50. }
  51. }
复制代码

这内里私有化了一个表达式树访问器,他的作用紧张是用来同步Lambda表达式内里的参数。

下面是调用方式

  1. var expression = LambdaExtension.True<ScoreClass>();
  2. if (!string.IsNullOrWhiteSpace(request.CourseName))
  3. expression = expression.And(e => e.CourseName.Contains(request.CourseName));
  4. if (!string.IsNullOrWhiteSpace(request.StudentName))
  5. expression = expression.And(et => et.StudentName.Contains(request.StudentName));
  6. var resultDatas = datas.Where(expression.Compile())
  7. .ToList();
  8. Console.WriteLine($"查询结果:\n{string.Join("\n", resultDatas.Select(e => $"{e.StudentName} {e.CourseName} {e.Score}"))}");
复制代码

where条件内里只能带委托,而我们的expression是Lambda表达式,所以必要Compile进行委托编译。

运行结果:

113355z0arsr3n2sfexzza.png

细致看代码,第一个条件And内里的参数是“e”,第二个条件内里的参数是et,同一个Lambda表达式内里(这里只有一个参数),参数肯定是一致的,所以在LambdaExtension类中,在合并两个Lambda表达式的时间,就必要将参数合并成一个。

经过这样的扩展,我们就可以根据我们的现实情况,拼凑好必要的表达式,得到我们想要的结果。

三、总结

表达式树方面的讲解,终于可以告一段落了。不停后没有这样的写文章,现在以为写文章还是真的挺累的,本年中秋节的这三天,算是全部的给博客园了。不外这三天讲解的内容,基本上把反面Dapper的扩展必要用的技能都铺垫了,反面我们就继续对ORM的讲解了。其实没写一篇博文,蜗牛都会去罗列和梳理相干知识点,这也让蜗牛获益匪浅,也盼望蜗牛的博客能资助到园友,这就是所谓的“赠人玫瑰,手留余香”吧。







来源:https://www.cnblogs.com/snailblog/archive/2019/09/15/11525118.html
C#论坛 www.ibcibc.com IBC编程社区
C#
C#论坛
IBC编程社区
*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则