一:背景

1. 讲故事

前几天看同事在用 linq 给内存中的两个 model 做左连接,用过的朋友都知道,你一定少不了一个叫做 DefaultIfEmpty 函数,这玩意吧,本来很流畅的 from...in...join, 突然搞进来这么一个函数,真的是恶心他妈给恶心开门,恶心到家了,简化后的代码如下:

class User{public int UserID { get; set; }public string Email { get; set; }}class Order{public int OrderID { get; set; }public string OrderTitle { get; set; }public int UserID { get; set; }}static void Main(string[] args){var userList = new List<User>(){new User(){ UserID=1, Email="333@qq.com"},new User(){ UserID=2, Email="444@qq.com"},};var orderList = new List<Order>(){new Order(){ OrderID=1, OrderTitle="订单1", UserID=1},new Order(){ OrderID=2, OrderTitle="订单2", UserID=1}};var query = from u in userListjoin o in orderList on u.UserID equals o.UserID into grpfrom item in grp.DefaultIfEmpty()select new { UserID = u.UserID, OrderTitle = item?.OrderTitle };       }    

之所以出现这个情况是因为不管是 查询关键词 还是 扩展方法,都并没有直接对 leftjoin 和 rightjoin 底层支持,只能通过变通的方式去实现,这就很尴尬了,比如说上面的这段代码,你很难在多天之后还能准确理解这里的 DefaultIfEmpty 是用来干嘛的,那现在问题的关键在于,有没有什么方法让底层支持或者有可信的第三方帮我封装好,还真巧,在 github 上 还真有一个 morelinq 项目:https://github.com/morelinq/MoreLINQ,看 md 是给 Enumerable 扩展了 60,70 个方法,如虎添翼呀,接下来一起来探索下吧。

二:MoreLinq 下的探索

1. 安装

安装非常简单,用 nuget 跑一下  Install-Package morelinq -Version 3.3.2 即可。

2. LeftJoin / RightJoin / FullJoin

在 morelinq 中就提供了 左外,右边,全连接,这就很????????了,提高开发效率,让我们更加专注业务,这里就使用 leftjoin 来改造刚才的代码,代码如下:

var query2 = userList.LeftJoin(orderList, u => u.UserID, o => o.UserID,u => new { UserID = u.UserID, OrderTitle = default(string) },(u, o) => new { UserID = u.UserID, OrderTitle = o.OrderTitle });

怎么样,一句链式就搞定了,而且代码还非常好理解。

  • 第一个参数:join 集合

  • 第二个参数:source 集合的关联 id

  • 第三个参数:join 集合的关联 id

  • 第四个参数:source 存在,join不存在 应该返回的 model 架构

  • 第五个参数:source,join 都存在      应该返回的 model 架构

刚才也说到了有60,70个扩展方法,大家可以去趴一趴其他有趣的东西,这里我推荐几个给大家演示一下,毕竟还是非常实用的。

3. Shuffle

从字面意思上看就是洗牌,挺实用的一个方法,很多时候我希望在一个集合中随机抽取一条记录,比如说我有10套邮件模板,当用户下订单之后,我希望可以随机抽一套模板给用户,以防被 qq邮箱 放入垃圾箱中,原来我需要是用 new guid 来实现,如下代码:

var list = new List<int>() { 1, 3, 5, 7, 9, 11, 12 };var query = list.OrderBy(m => Guid.NewGuid());Console.WriteLine(string.Join(",",query));---- output -----11,7,9,12,5,3,1

现在就简单多了,直接使用 Shuffle 搞定。

var list = new List<int>() { 1, 3, 5, 7, 9, 11, 12 };var query = list.Shuffle();Console.WriteLine(string.Join(",", query));----- output ------5,1,9,12,7,3,11

4.  Insert

有时候我需要在 IEnumerable 集合的指定位置插入一个集合,举个例子, A= { 1, 3, 5, 7, 9, 11, 12 }, B ={8}, 我希望将 8 插入到 7 和 9 之间,在现有的 Enumerable 下只有 Concat 和 Append 方法,无法做到指定插入,这个需求又可以被 moreqlinq 搞定啦。。。代码如下:

IEnumerable<int> list = new List<int>() { 1, 3, 5, 7, 9, 11, 12 };var query = list.Insert(new List<int>() { 8 }, 4);Console.WriteLine(string.Join(",", query));

可以看到往一个集合的指定位置插入一个集合就是这么轻松如意,太爽啦~~~

5. ForEach

不知道什么原因,至今在 IEnumerable 下都没有提供 ForEach 扩展方法,我这个升斗小民反正是体会不到这么设计的哲学在哪里,在原来你只能 ToList 立即执行,要么使用 foreach 进行延期遍历,现在就方便多了,简化的代码如下:

IEnumerable<int> list = new List<int>() { 1, 3, 5, 7, 9, 11, 12 };list.ForEach(m =>{Console.Write(m+" ");});

6. ToDataTable

对在看的各位大佬估计都用不上,对我们公司几个 10 + 年的项目,那是万万不能少哈,如有能用得上的,可以简单看一下:

非常简单,不过我还是好奇一下它是怎么做到的,可以用 ilspy 去翻翻它的源码:


public static TTable ToDataTable<T, TTable>(this IEnumerable<T> source, TTable table, params Expression<Func<T, object>>[] expressions) where TTable : DataTable
{MemberInfo[] members = PrepareMemberInfos(expressions).ToArray();members = BuildOrBindSchema(table, members);Func<T, object[]> func = CreateShredder<T>(members);table.BeginLoadData();try{foreach (T item in source){DataRow dataRow = table.NewRow();dataRow.ItemArray = func(item);table.Rows.Add(dataRow);}return table;}finally{table.EndLoadData();}
}private static IEnumerable<MemberInfo> PrepareMemberInfos<T>(ICollection<Expression<Func<T, object>>> expressions)
{if (expressions == null || expressions.Count == 0){return typeof(T).GetMembers(BindingFlags.Instance | BindingFlags.Public).Where(delegate(MemberInfo m){if (m.MemberType != MemberTypes.Field){PropertyInfo propertyInfo = m as PropertyInfo;if ((object)propertyInfo != null && propertyInfo.CanRead){return propertyInfo.GetIndexParameters().Length == 0;}return false;}return true;});}try{return expressions.Select(GetAccessedMember);}catch (ArgumentException innerException){throw new ArgumentException("One of the supplied expressions is not allowed.", "expressions", innerException);}MemberInfo GetAccessedMember(LambdaExpression lambda){Expression expression = lambda.Body;if (expression.NodeType == ExpressionType.Convert || expression.NodeType == ExpressionType.ConvertChecked){expression = ((UnaryExpression)expression).Operand;}MemberExpression memberExpression = expression as MemberExpression;if (memberExpression == null || memberExpression.Expression.NodeType != ExpressionType.Parameter){throw new ArgumentException($"Illegal expression: {lambda}", "lambda");}return memberExpression.Member;}
}

从上面源码大概可以看到,将 List 转成 DataTable 支持两种方式,要么反射,要么 Expression 解析树,默认用的是反射,性能要稍微低一点。

三:总结

当然这里还有很多的扩展方法,篇幅原因恕不能一一介绍,有兴趣的朋友可以pull下来试一试,总的来说这种工具类太棒了,让我们可以更好的专注于业务。

Linq 下的扩展方法太少了,您期待的 MoreLinq 来啦相关推荐

  1. Linq 下的 Take() 方法内部机制是怎样的?

    咨询区 Rahul Kishore: 我的web需要访问数据库,但是表比较大,我仅仅想要获取该表中 N 条数据,我查阅了 MSDN 文档,看到了一个 Take() 方法,我现在很疑惑它的运行机制是下面 ...

  2. Linq快速入门——扩展方法

    Linq为我们提供了许多扩展方法,方便我们对数据源进行操作(Where,Select...).即使你不了解算法,也能使用Linq当回牛人.扩展方法本质并不是什么高深的技术,说白了就是一个Static静 ...

  3. Enumerable 下又有新的扩展方法啦,快来一睹为快吧

    一:背景 1. 讲故事 前段时间将公司的一个项目从 4.5 升级到了 framework 4.8 ,编码的时候发现 Enumerable 中多了三个扩展方法: Append, Prepend, ToH ...

  4. C# 3.0 —— 扩展方法

    扩展方法是C# 3.0新加入的特性,允许我们在不改变源代码的情况下扩展(即填加)现有类型中的实例方法,也给我们提供了另外一种扩展类型行为的方法(其它的方法为继承.组合.反射). 下面我们来看一个代码示 ...

  5. [C# 基础知识系列]专题十五:全面解析扩展方法

    引言:  C# 3中所有特性的提出都是更好地为Linq服务的, 充分理解这些基础特性后.对于更深层次地去理解Linq的架构方面会更加简单,从而就可以自己去实现一个简单的ORM框架的,对于Linq的学习 ...

  6. C#学习笔记四: C#3.0自动属性匿名属性及扩展方法

    前言 这一章算是看这本书最大的收获了, Lambda表达式让人用着屡试不爽, C#3.0可谓颠覆了我们的代码编写风格. 因为Lambda所需篇幅挺大, 所以先总结C#3.0智能编译器给我们带来的诸多好 ...

  7. [易学C#]C#3.0语言新特性之扩展方法

    当我们需要对已有类的功能进行扩展时,我们通常会想到继承,继承已有类,然后为其加入新的行为.而C# 3.0中加入的扩展方法(Extension Methods)特性,则提供了另一种实现功能扩展的方式. ...

  8. C#中的扩展方法学习总结

      版权声明:本文由秦元培创作和发表,采用署名(BY)-非商业性使用(NC)-相同方式共享(SA)国际许可协议进行许可,转载请注明作者及出处,本文作者为秦元培,本文标题为C#中的扩展方法学习总结,本文 ...

  9. C#.Net工作笔记010---c#中的静态扩展方法_可动态给string等_添加共通方法好用

    技术交流QQ群[JAVA,C++,Python,.NET,BigData,AI]:170933152 之前,给list添加排序的扩展方法的时候用过.下面的作用是去掉list中重复的数据. /// &l ...

最新文章

  1. oracle 一个实例创建多个数据库_oracle 一个实例创建多个数据库
  2. Factory Method工厂方法模式
  3. 漫画 | 这样的男朋友,让我分分钟想剖腹自尽!
  4. pid matlab 温度控制,基于MatlabPID温控系统设计与仿真.doc
  5. Swift傻傻分不清楚系列(十)枚举
  6. 20101008 搬家
  7. 热门项目:高精度图像分类全流程开发
  8. .net知识和学习方法系列(三)CSharp中控件台的输入输出
  9. 如何不起协议,R1ping通R3
  10. 阿里云香港服务器和大陆服务器区别及选择
  11. CNTV CBOX的服务项
  12. 8位处理器、16位处理器、32位处理器和64位处理器
  13. 3. 自定义Java编译时注解处理器
  14. 微信自定义分享操作步骤
  15. 计算机无法设置双屏显示,win10无法设置双屏显示怎么办_win10系统设置双屏显示失败如何解决...
  16. RK3399 Android7.1实时读取当前cpu频率
  17. java jdk1.8.0_221 安装步骤
  18. 指令在Vue.js 2.0中的变化
  19. Java实验——定义一个表示学生信息的类Student,要求如下:
  20. 互联网及相关公司的求职经历分享

热门文章

  1. redis集群报Jedis does not support password protected Redis Cluster configurations异常解决办法...
  2. 程序一启动检查网络,如果没有网络就退出程序
  3. WPF 2D绘图(2)Geometry
  4. [未来的购碟指南]送给那些以后想收藏真人电影DVD的菜鸟们
  5. 怎样制作滴滴截图_滴滴老了吗?
  6. 如何获取租户中所有的Team
  7. 注册表被黑客篡改 怎样修复_使用快速注册表黑客设置Office 2007配色方案
  8. python中的logger模块详细讲解
  9. productFlavors设置signingConfig不管用的问题
  10. #51CTO学院四周年# 还好没放弃,终于等到你~