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

欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

何止 Linq 的 Distinct 不給力

系統 1851 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国产精| 日韩高清中文字幕 | 91麻豆精品久久久久蜜臀 | 久草看片| 成人在线小视频 | 亚洲已满18点击进入在线观看 | 香港一级毛片在线播放 | 午夜视频在线观看网站 | 婷婷亚洲综合五月天小说 | 日本精品久久久久久久久免费 | 日韩亚洲欧美视频 | 99精品国产免费久久国语 | 国产在线观看免费 | 污视频在线免费观看 | 亚洲成人黄色在线 | 欧美特级| 欧美高清在线精品一区 | 日本视频一区在线观看免费 | 日本一级毛片视频 | 久久久久久久国产精品 | 超碰在线播 | 久久中文网 | 国产欧美亚洲精品a | 91精品在线看 | 色天天爱天天狠天天透 | 亚洲一区二区三区在线播放 | 成人黄色在线视频 |