• 如何正确看待Linq的DistinctBy扩展和ForEach扩展


    在微软标准的Linq中,并没有DistinctBy扩展和ForEach扩展,但在平时使用工作中却又经常需要使用到这两个功能,照理来说,微软在Linq中应该包含这两个扩展才对,可事实上为什么并没有呢?本文我就来说说自己对这两个扩展的理解!

    关于DistinctBy扩展

    顾名思义,DistinctBy扩展就是根据一个键值进行唯一性的筛选,将有重复键值的元素剔除,仅保留一个!当然Linq中有Distinct扩展,但其功能简直是弱爆了!用过的同志相信都对Distinct扩展吐槽无数遍了吧!如果你要使用Distinct扩展实现DistinctBy扩展的功能,还要专门定义一个辅助类!Oh,My God!这简直是对程序员的谋杀!但是等经历过无数个纠结之后,我突然发现,微软在标准的Linq中实际上是包含了DistinctBy扩展的功能的,只不过不那么直接,看下面的示例代码:

     1 class Person
     2         {
     3             public int Age { get; set; }
     4             public string Name { get; set; }
     5             public override string ToString()
     6             {
     7                 return string.Format("Age:{0}  Name:{1}", Age, Name);
     8             }
     9         }
    10         [STAThread]
    11         static void Main()
    12         {
    13             var persons = new[] { 
    14                 new Person{Age = 10,Name="a"},
    15                 new Person{Age = 10,Name="b"},
    16                 new Person{Age = 10,Name="c"},
    17                 new Person{Age = 20,Name="d"}
    18             };
    19             foreach (var p in persons.GroupBy(o=>o.Age).Select(g=>g.First()))
    20             {
    21                 Console.WriteLine(p);
    22             }
    23         }

    运行结果

    从结果看,代码成功完成了根据键值Age进行Distinct的操作。

    明眼人可能一眼就看出来了,不错,就是使用GroupBySelectFirst这三个子操作组合出DistinctBy的功能!只不过实现一个DistinctBy功能需要写这么做代码实在是不好,于是可以封装一下,把GroupBy、Select和First这三个子操作的组合封装成一个DistinctBy扩展方法,就可以方便的使用了。封装的代码 too simple,就不贴上来了!

    关于ForEach扩展

    为什么微软不在Linq中添加ForEach扩展,这个问题的讨论在网上已经很多了,总结一下主要是有下面几点原因:

    1.Linq中已经有Select扩展了,因此不必在实现一个ForEach,因为在大多数情况下可以用Select来实现ForEach的功能(当然我不建议这样做,因为Select是延迟操作,如果仅仅实现ForEach功能,有些时候代码不能够按照设计意图正确运行);

    2.ForEach破坏了Linq的编程模式,就是说破坏了链式编程模式,所谓链式编程,大概的意思就是将多个操作通过点号"."链接在一起,相信写过Linq的同志很清楚这句话的含义吧!

    我看到网上有人这么来设计ForEach扩展:

    1 public static void ForEach<T>(this IEnumerable<T> source, Action<T> foreachAction)
    2         {
    3             foreach (var t in source)
    4             {
    5                 foreachAction(t);
    6             }
    7         }

    我不得不说这是简直是对Linq的“亵渎”啊,试想,如果别人使用了你的这个ForEach之后,后续操作岂不是成天方夜谭了吗?所以说这样设计ForEach是万万不可的!即使勉强要设计,也要设计成这样才对啊!

    1 public static IEnumerable<T> ForEach<T>(this IEnumerable<T> source, Action<T> foreachAction)
    2         {
    3             foreach (var t in source)
    4             {
    5                 foreachAction(t);
    6             }
    7             return source;
    8         }

    而且在我看来,这样添加ForEach扩展并不妥当,原因在于:这样设计的ForEach扩展,破坏了Linq的延迟操作特性!

    所以说,我认为微软不在Linq中包含ForEach扩展算是一个正确的选择,如果要用到ForEach功能,还是老老实实用foreach语句来写吧!其实也并不复杂!

  • 相关阅读:
    Atitit.ide eclipse编译速度慢的解决
    Atitit.ide eclipse编译速度慢的解决
    Atitit.可视化与报表原理与概论
    Atitit.可视化与报表原理与概论
    Atitit.数据检索与网络爬虫与数据采集的原理概论
    Atitit.数据检索与网络爬虫与数据采集的原理概论
    Atitit 游戏的原理与概论attilax总结
    Atitit 游戏的原理与概论attilax总结
    Atiti.ui原理与gui理论
    Atiti.ui原理与gui理论
  • 原文地址:https://www.cnblogs.com/ILoveSleep/p/3174799.html
Copyright © 2020-2023  润新知