2008-09-16 62 views

回答

2

這是MSDN有什麼看法的IEqualityComparer(非通用):

該接口允許對集合定製相等比較的實施。也就是說,您可以創建您自己的相等定義,並指定將此定義與接受IEqualityComparer接口的集合類型一起使用。在.NET Framework中,Hashtable,NameValueCollectionOrderedDictionary集合類型的構造函數接受此接口。

此接口僅支持相等比較。用於分類和排序的比較定製由接口提供。

它看起來像這個接口的通用版本執行相同的功能,但用於Dictionary<(Of <(TKey, TValue>)>)集合。

就您自己的目的使用此接口的最佳做法。我會說最好的做法是在你派生或實現一個類,這個類與上面提到的.NET框架集合有類似的功能,並且你希望爲你自己的集合添加相同的功能時使用它。這將確保您與.NET框架如何使用該界面一致。

換句話說,如果您正在開發自定義集合,並且希望允許您的用戶控制用於許多LINQ和集合相關方法(例如排序)的平等,則支持使用此接口。

1

我會說最好的用法是當你需要爲特定算法插入不同的相等規則時。很多相同的方式排序算法可能接受IComparer<T>,這一發現算法可能接受IEqualityComparer<T>

1

列表使用此接口很多,所以可以說a.Substract(b)或其他的這些漂亮的功能。

請記住:如果您的對象不會返回相同的哈希碼,則不會調用Equals。

5

我做了以下工作,我不確定它是否是現實世界的最佳實踐,但對我來說工作得很好。 :)

public class GenericEqualityComparer<T> : IEqualityComparer<T> 
{ 
    private Func<T, T, Boolean> _comparer; 
    private Func<T, int> _hashCodeEvaluator; 
    public GenericEqualityComparer(Func<T, T, Boolean> comparer) 
    { 
     _comparer = comparer; 
    } 

    public GenericEqualityComparer(Func<T, T, Boolean> comparer, Func<T, int> hashCodeEvaluator) 
    { 
     _comparer = comparer; 
     _hashCodeEvaluator = hashCodeEvaluator; 
    } 

    #region IEqualityComparer<T> Members 

    public bool Equals(T x, T y) 
    { 
     return _comparer(x, y); 
    } 

    public int GetHashCode(T obj) 
    { 
     if(obj == null) { 
      throw new ArgumentNullException("obj"); 
     } 
     if(_hashCodeEvaluator == null) { 
      return 0; 
     } 
     return _hashCodeEvaluator(obj); 
    } 

    #endregion 
} 

然後,您可以在您的收藏中使用它。

var comparer = new GenericEqualityComparer<ShopByProduct>((x, y) => x.ProductId == y.ProductId); 
var current = SelectAll().Where(p => p.ShopByGroup == group).ToList(); 
var toDelete = current.Except(products, comparer); 
var toAdd = products.Except(current, comparer); 

如果需要支持自定義的GetHashCode()功能,使用替代構造提供拉姆達做替代計算:

var comparer = new GenericEqualityComparer<ShopByProduct>(
     (x, y) => { return x.ProductId == y.ProductId; }, 
     (x) => { return x.Product.GetHashCode()} 
); 

我希望這有助於。 =)

+1

問題:不能認爲`obj.GetHashCode()`是有意義的。請參閱我的帖子中的鏈接:http://stackoverflow.com/questions/74032/whats-the-recommended-best-practice-for-using-iequalitycomparert/4679491#4679491 – 2011-01-13 11:28:17

11

任何時候如果您考慮使用IEqualityComparer<T>,請暫時考慮是否可以使用類來實現IEquatable<T>。如果一個Product應該總是通過ID進行比較,那麼只需將它定義爲等同就可以使用默認比較器。

儘管如此,仍有一些原因,你可能需要自定義比較:如果有可能被認爲是相等的一類的多種方式實例

  1. 。最好的例子是一個字符串,框架在StringComparer中提供了6個不同的比較器。
  2. 如果該類定義的方式不能將其定義爲IEquatable<T>。這將包括其他人定義的類和由編譯器生成的類(特別是匿名類型,默認情況下使用屬性明智的比較)。

如果您確實需要比較器,您當然可以使用通用比較器(請參閱DMenT的答案),但是如果您需要重用該邏輯,則應該將其封裝在專用類中。你甚至可以通過從通用基繼承其聲明:

class ProductByIdComparer : GenericEqualityComparer<ShopByProduct> 
{ 
    public ProductByIdComparer() 
     : base((x, y) => x.ProductId == y.ProductId, z => z.ProductId) 
    { } 
} 

至於使用,您應該採取comparers的優勢在可能的情況。例如,與每個用作字典鍵的字符串(應用程序中散佈的邏輯字符)相比,不要致電ToLower(),您應該聲明字典使用不區分大小寫的StringComparer。接受比較器的LINQ運算符也是如此。但是,再次,總是要考慮應該是班級固有的可比較的行爲,而不是外部定義的行爲。

相關問題