如何正確看待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語句來寫吧!其實也並不復雜!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM