作為參數,調用時大多都要創建新的類去實現這個接口,很不給力。文中給出了一種解決辦法,略顯煩索,我也寫了《c#擴展方法奇思妙用基礎篇八:Distinct擴展》一文使用擴展方法予以簡化。但問題遠遠沒有結束,不給力是因為使用了IEqualityComparer作為參數,而.net中將IEqualityCom" />

亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

何止 Linq 的 Distinct 不給力

系統 1784 0

昨日看到一篇文章 《 Linq的Distinct太不給力了 》,文中指出 Linq 中 Distinct 方法的一個重載使用了 IEqualityComparer<T> 作為參數,調用時大多都要創建新的類去實現這個接口,很不給力。文中給出了一種解決辦法,略顯煩索,我也寫了《 c# 擴展方法 奇思妙用 基礎篇 八:Distinct 擴展 》一文使用 擴展方法 予以簡化。

但問題遠遠沒有結束,不給力是因為使用了 IEqualityComparer<T> 作為參數,而 .net 中將 IEqualityComparer<T> 用作參數的地方相當多:

IEqualityComparer<T> 用作參數

.net 中 IEqualityComparer<T> 用作參數,大致可分為以下兩種情況:

1. Linq

            
              1
            
            
              2
            
            
              3
            
            
              4
            
            
              5
            
            
              6
            
            
              7
            
            
              8
            
            
              9
            
            
              10
            
            
              11
            
            
              12
            
            
              13
            
            
              14
            
            
              15
            
            
              16
            
            
              17
            
            
              18
            
            
              19
            
            
              20
            
          
            
              public
            
            
              static
            
            
              class
            
             Enumerable

{

    
            
              public
            
            
              static
            
            
              bool
            
             Contains<TSource>(
            
              this
            
             IEnumerable<TSource> source, TSource 
            
              value
            
            , 
            
              IEqualityComparer<TSource>
            
             comparer);

    
            
              public
            
            
              static
            
             IEnumerable<TSource> Distinct<TSource>(
            
              this
            
             IEnumerable<TSource> source, 
            
              IEqualityComparer<TSource>
            
             comparer);

    
            
              public
            
            
              static
            
             IEnumerable<TSource> Except<TSource>(
            
              this
            
             IEnumerable<TSource> first, IEnumerable<TSource> second,

        
            
              IEqualityComparer<TSource>
            
             comparer);

    
            
              public
            
            
              static
            
             IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(
            
              this
            
             IEnumerable<TSource> source,

        Func<TSource, TKey> keySelector, 
            
              IEqualityComparer<TKey>
            
             comparer);

    
            
              public
            
            
              static
            
             IEnumerable<TSource> Intersect<TSource>(
            
              this
            
             IEnumerable<TSource> first, IEnumerable<TSource> second,

       
            
               IEqualityComparer<TSource>
            
             comparer);

    
            
              public
            
            
              static
            
            
              bool
            
             SequenceEqual<TSource>(
            
              this
            
             IEnumerable<TSource> first, IEnumerable<TSource> second,

        
            
              IEqualityComparer<TSource>
            
             comparer);

    
            
              public
            
            
              static
            
             Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(
            
              this
            
             IEnumerable<TSource> source,

        Func<TSource, TKey> keySelector, 
            
              IEqualityComparer<TKey> comparer
            
            );

    
            
              public
            
            
              static
            
             ILookup<TKey, TSource> ToLookup<TSource, TKey>(
            
              this
            
             IEnumerable<TSource> source, Func<TSource, TKey> keySelector,

       
            
               IEqualityComparer<TKey>
            
             comparer);

    
            
              public
            
            
              static
            
             IEnumerable<TSource> Union<TSource>(
            
              this
            
             IEnumerable<TSource> first, IEnumerable<TSource> second,

        
            
              IEqualityComparer<TSource>
            
             comparer);

    
            
              //...
            
            

}
          

同樣 Queryable 類中也有類似的一些方法

2. 字典、集合類

            
              1
            
            
              2
            
            
              3
            
            
              4
            
            
              5
            
            
              6
            
            
              7
            
            
              8
            
            
              9
            
            
              10
            
            
              11
            
            
              12
            
            
              13
            
            
              14
            
            
              15
            
            
              16
            
            
              17
            
            
              18
            
          
            
              19
            
            

20
          
            
              public
            
            
              class
            
             Dictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, 
          
                IEnumerable<KeyValuePair<TKey, TValue>>, IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback

{

    
            
              public
            
             Dictionary();

    
            
              public
            
             Dictionary(IDictionary<TKey, TValue> dictionary);

    
            
              public
            
             Dictionary(
            
              IEqualityComparer<TKey>
            
             comparer);

    
            
              public
            
             Dictionary(
            
              int
            
             capacity);

    
            
              public
            
             Dictionary(IDictionary<TKey, TValue> dictionary, 
            
              IEqualityComparer<TKey>
            
             comparer);

    
            
              public
            
             Dictionary(
            
              int
            
             capacity, 
            
              IEqualityComparer<TKey>
            
             comparer);

    
            
              //...
            
            

}




            
              public
            
            
              class
            
             HashSet<T> : ISerializable, IDeserializationCallback, ISet<T>, ICollection<T>, IEnumerable<T>, IEnumerable

{

    
            
              public
            
             HashSet();

    
            
              public
            
             HashSet(IEnumerable<T> collection);

    
            
              public
            
             HashSet(
            
              IEqualityComparer<T>
            
             comparer);

    
            
              public
            
             HashSet(IEnumerable<T> collection, 
            
              IEqualityComparer<T>
            
             comparer);

    
            
              //...
            
            

}
          

Dictionary<TKey, TValue> 和 HashSet<T> 類的構造函數都用到了 IEqualityComparer<T> 接口。

除了如上兩個,還有 ConcurrentDictionary<TKey, TValue>、SortedSet<T>、KeyedCollection<TKey, TItem>(抽象類)、SynchronizedKeyedCollection<K, T> 等等也使用 IEqualityComparer<T> 接口作為構造函數的參數。

?

IEqualityComparer<T> 作為參數多在復雜的重載中出現,滿足一些特殊情況的要求,而相應的簡單的重載確是經常使用的。因此,雖然 IEqualityComparer<T> 在 .net 應用廣泛,但在我們編程時,確是較少涉及。
不過話又說回來,一旦使用到時,就會感覺相當麻煩。多數時候你不得不去創建一個新類,去實現 IEqualityComparer<T> 接口,再去 new 一個實例,而你真正需要的可能僅僅是根據某個屬性(如 ID )進行比較。創建新類實現 IEqualityComparer<T> 接口,不但增加了代碼量,還增加的復雜度:你要考慮這個新類放在哪里合適,如何命名等等。

因此,我們期望有一個簡單的方法來能直接創建 IEqualityComparer<T> 的實例。《 c# 擴展方法 奇思妙用 基礎篇 八:Distinct 擴展 》一文中給出了一個簡單實用的類 CommonEqualityComparer<T, V>,在這里可以復用來達到我們的目標。

CommonEqualityComparer<T, V>

            
              1
            
            
              2
            
            
              3
            
            
              4
            
            
              5
            
            
              6
            
            
              7
            
            
              8
            
            
              9
            
            
              10
            
            
              11
            
            
              12
            
            
              13
            
            
              14
            
            
              15
            
            
              16
            
            
              17
            
            
              18
            
            
              19
            
            
              20
            
            
              21
            
            
              22
            
            
              23
            
            
              24
            
            
              25
            
            
              26
            
            
              27
            
            
              28
            
          
            
              using
            
             System;


            
              using
            
             System.Collections.Generic;


            
              using
            
             System.Runtime.CompilerServices;


            
              using
            
             System.Linq;




            
              public
            
            
              class
            
             CommonEqualityComparer<T, V> : IEqualityComparer<T>

{

    
            
              private
            
             Func<T, V> keySelector;

    
            
              private
            
             IEqualityComparer<V> comparer;



    
            
              public
            
             CommonEqualityComparer(Func<T, V> keySelector, IEqualityComparer<V> comparer)

    {

        
            
              this
            
            .keySelector = keySelector;

        
            
              this
            
            .comparer = comparer;

    }

    
            
              public
            
             CommonEqualityComparer(Func<T, V> keySelector)

        : 
            
              this
            
            (keySelector, EqualityComparer<V>.Default)

    {  }



    
            
              public
            
            
              bool
            
             Equals(T x, T y)

    {

        
            
              return
            
             comparer.Equals(keySelector(x), keySelector(y));

    }

    
            
              public
            
            
              int
            
             GetHashCode(T obj)

    {

        
            
              return
            
             comparer.GetHashCode(keySelector(obj));

    }

}
          

使用這個類,可以簡易通過 lambda 表達式來創建 IEqualityComparer<T> 的實例:

            
              1
            
            
              2
            
            
              3
            
            
              4
            
            
              5
            
            
              6
            
          
            
              var
            
             dict = 
            
              new
            
             Dictionary<Person, 
            
              string
            
            >(
            
              
                new
              
               CommonEqualityComparer<Person, 
              
                string
              
              >(p => p.Name)
            
            );



List<Person> persons = 
            
              null
            
            ;

Person p1 = 
            
              null
            
            ;


            
              //...
            
            
              var
            
             ps = persons.Contains(p1, 
            
              
                new
              
               CommonEqualityComparer<Person, 
              
                int
              
              >(p=>p.ID)
            
            );
          

相信看了上面代碼的,你會覺得 new CommonEqualityComparer<Person, string>(p => p.Name)) 太冗長。不過我們可以借助下面的類加以改善:

            
              1
            
            
              2
            
            
              3
            
            
              4
            
            
              5
            
            
              6
            
            
              7
            
            
              8
            
            
              9
            
            
              10
            
            
              11
            
          
            
              public
            
            
              static
            
            
              class
            
             Equality<T>

{

    
            
              public
            
            
              static
            
             IEqualityComparer<T> CreateComparer<V>(Func<T, V> keySelector)

    {

        
            
              return
            
            
              new
            
             CommonEqualityComparer<T, V>(keySelector);

    }

    
            
              public
            
            
              static
            
             IEqualityComparer<T> CreateComparer<V>(Func<T, V> keySelector, IEqualityComparer<V> comparer)

    {

        
            
              return
            
            
              new
            
             CommonEqualityComparer<T, V>(keySelector, comparer);

    }

}
          

調用代碼可簡化:

            
              1
            
            
              2
            
          
            
              var
            
             dict = 
            
              new
            
             Dictionary<Person, 
            
              string
            
            >(
            
              Equality<Person>.CreateComparer(p => p.Name)
            
            );


            
              var
            
             ps = persons.Contains(p1, 
            
              Equality<Person>.CreateComparer(p => p.ID)
            
            );
          

不考慮類名和方法名的前提下, Equality<Person>.CreateComparer(p => p.ID) 的寫法也經精簡到極限了 (如果你能進一步精簡,不妨告訴我)

其實有了 Equality<T> 這個類,我們大可將 CommonEqualityComparer<T, V> 類封裝隱藏起來。

Equality<T> 類

            
              1
            
            
              2
            
            
              3
            
            
              4
            
            
              5
            
            
              6
            
            
              7
            
            
              8
            
            
              9
            
            
              10
            
            
              11
            
            
              12
            
            
              13
            
            
              14
            
            
              15
            
            
              16
            
            
              17
            
            
              18
            
            
              19
            
            
              20
            
            
              21
            
            
              22
            
            
              23
            
            
              24
            
            
              25
            
            
              26
            
            
              27
            
            
              28
            
            
              29
            
            
              30
            
            
              31
            
            
              32
            
            
              33
            
            
              34
            
            
              35
            
          
            
              public
            
            
              static
            
            
              class
            
             Equality<T>

{

    
            
              public
            
            
              static
            
             IEqualityComparer<T> CreateComparer<V>(Func<T, V> keySelector)

    {

        
            
              return
            
            
              new
            
             CommonEqualityComparer<V>(keySelector);

    }

    
            
              public
            
            
              static
            
             IEqualityComparer<T> CreateComparer<V>(Func<T, V> keySelector, IEqualityComparer<V> comparer)

    {

        
            
              return
            
            
              new
            
             CommonEqualityComparer<V>(keySelector, comparer);

    }



    
            
              class
            
             CommonEqualityComparer<V> : IEqualityComparer<T>

    {

        
            
              private
            
             Func<T, V> keySelector;

        
            
              private
            
             IEqualityComparer<V> comparer;



        
            
              public
            
             CommonEqualityComparer(Func<T, V> keySelector, IEqualityComparer<V> comparer)

        {

            
            
              this
            
            .keySelector = keySelector;

            
            
              this
            
            .comparer = comparer;

        }

        
            
              public
            
             CommonEqualityComparer(Func<T, V> keySelector)

            : 
            
              this
            
            (keySelector, EqualityComparer<V>.Default)

        { }



        
            
              public
            
            
              bool
            
             Equals(T x, T y)

        {

            
            
              return
            
             comparer.Equals(keySelector(x), keySelector(y));

        }

        
            
              public
            
            
              int
            
             GetHashCode(T obj)

        {

            
            
              return
            
             comparer.GetHashCode(keySelector(obj));

        }

    }

}
          

CommonEqualityComparer<T, V> 封裝成了 Equaility<T> 的嵌套類 CommonEqualityComparer<V>,對外不可見,降低了使用的復雜度。

c# 擴展方法 奇思妙用 基礎篇 八:Distinct 擴展 》一文中的 Distinct 擴展方法 寫起來也簡單了:

            
              1
            
            
              2
            
            
              3
            
            
              4
            
            
              5
            
            
              6
            
            
              7
            
            
              8
            
            
              9
            
            
              10
            
            
              11
            
          
            
              public
            
            
              static
            
            
              class
            
             DistinctExtensions

{

    
            
              public
            
            
              static
            
             IEnumerable<T> Distinct<T, V>(
            
              this
            
             IEnumerable<T> source, Func<T, V> keySelector)

    {

        
            
              return
            
             source.Distinct(
            
              Equality<T>.CreateComparer(keySelector)
            
            );

    }

    
            
              public
            
            
              static
            
             IEnumerable<T> Distinct<T, V>(
            
              this
            
             IEnumerable<T> source, Func<T, V> keySelector, IEqualityComparer<V> comparer)

    {

        
            
              return
            
             source.Distinct
            
              (Equality<T>.CreateComparer(keySelector, comparer)
            
            );

    }

}
          

Linq 中除 Distinct 外還有眾多方法使用了 IEqualityComparer<T> 接口,逐一擴展未必是一個好方式,使用 Equality<T>.CreateComparer 方法比較明智。

總結

.net 中經常把 IEqualityComparer<T> 用作某些重載的參數。
雖然這些重載在日常使用中并不頻繁,不過一旦用到,大多要創建新類實現 IEqualityComparer<T>,繁瑣不給力。
本文創建 Equality<T> 泛型類,配合一個 lambda 表達式可快速創建 IEqualityComparer<T> 的實例。

何止 Linq 的 Distinct 不給力


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 成人小视频在线观看免费 | 日本一线一区二区三区免费视频 | www.夜夜骑| 久久亚洲国产视频 | 色啦啦在线观看 | 婷婷春色| 高清一区二区 | 天天摸夜夜摸夜夜狠狠摸 | 成人国产精品一级毛片了 | 亚洲免费福利 | 中文字幕综合在线 | 久久综合久久综合久久综合 | 午夜在线社区视频 | 激情影院费观看 | 另类av| 性孕妇video国产中国 | 天天久久狠狠伊人第一麻豆 | 亚洲精品色综合久久 | 一级毛片高清免费播放 | 欧美一级亚洲一级 | 国产精品久久在线 | 欧洲免费无线码二区5 | 97色老99久久九九爱精品 | xxxxxx国产精品视频 | 亚洲国产精品久久久久网站 | 999精品久久久中文字幕蜜桃 | 噜噜色综合 | 亚洲精品国产一区二区图片欧美 | 色综合久久88色综合天天小说 | 四虎影视免费在线观看 | 日本一级成人毛片免费观看 | 国产成人亚洲欧美三区综合 | 大狠狠大臿蕉香蕉大视频 | 在线精品一区二区三区 | 最近免费中文字幕大全免费版视频 | 精品哟哟哟国产在线观看不卡 | 99热最新网站地址获取 | 国产99在线 | 亚洲 | 国产成+人+综合+亚洲不卡 | 久久国产精品99精品国产 | 国产精品一国产精品免费 |