2013-12-17 60 views
3

我有一個類爲什麼我的動態IEqualityComparer不起作用?

public class Foo 
{ 
    public int ID { get; set; } 
} 

,我已經實現了一個LinqEqualityComparer以允許除extenion方法動態的IEqualityComparer測試。

public class LinqEqualityComparer<T> : IEqualityComparer<T> 
{ 
    protected Func<T, T, bool> Comparison { get; set; } 

    public LinqEqualityComparer(Func<T, T, bool> comparison) 
    { 
     Comparison = comparison; 
    } 

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


    public int GetHashCode(T obj) 
    { 
     return obj.GetHashCode(); 
    } 
} 

我已經創建了下面的代碼來測試它:

IEnumerable<Foo> settings = new Foo[] 
{ 
    new Foo{ID = 1}, 
    new Foo{ID = 2} 
}; 
IEnumerable<Foo> currentSettings = new Foo[] 
{ 
    new Foo{ID = 1}, 
    new Foo{ID = 2}, 
    new Foo{ID = 3} 
}; 
IEqualityComparer<Foo> comparer = new LinqEqualityComparer<Foo>((x, y) => x.ID == y.ID); 
IEnumerable<Foo> missing = currentSettings.Except(settings, comparer); 

然而FOOS 1,2和3都存在於 '丟失' 的變量。

爲什麼LinqEqualityComparer不起作用?

+0

注意,這應該有一個稍微不同的名稱;這裏的想法是從一個委託(或更通常的lambda)定義一個比較器。雖然這與LINQ有些相關,但並不需要。 LINQ以外的地方有很多需要比較器的地方,因此我會考慮給它一個不同的名稱。 – Servy

回答

8

因爲您的相等比較器沒有正確執行GetHashCodeGetHashCode實施必須產生相同的代碼比較相等的元素。這裏不會發生這種情況,因爲相等比較是自定義的,而哈希碼不是相應生成的。

爲了使這項工作,你需要做兩件事情之一:

  1. 充分利用比較器接受的哈希碼實現作爲一個額外的參數,即x => x.ID.GetHashCode()並轉發了這一點。這是最簡單的,你應該在實踐中做什麼。

  2. 以這樣的方式修改GetHashCode,使得它是參與比較的屬性的哈希代碼的集合函數(這裏是ID屬性) - 單個哈希代碼的直xor將起作用(儘管它可能不是最佳的)。

    這給您帶來了如何檢測哪些屬性被比較的問題。爲了能夠自動回答該問題,您需要接受表達式樹而不是委託進行比較,即Expression<Func<T, T, bool>>,然後訪問表達式樹以確定要執行的操作。這肯定不容易。

+0

喬恩,這是有道理的 - 我也應該通過一個合適的散列函數? – Liath

+0

@Lath是的,構造函數需要一個'Func '委託,這個委託也與生成正確哈希代碼的相應'比較'代表配對。 –

+1

爲了編輯,他的'GetHashCode'實現應該是'x => x.ID.GetHashCode()'。這就是全部...... – Servy