我有一个班级
public class Foo
{
public int ID { get; set; }
}
我实现了一个LinqEqualityComparer,允许对Except 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都存在于'missing'变量中。
为什么这个LinqEqualityComparer不起作用?
答案 0 :(得分:8)
因为您的相等比较器没有正确实现GetHashCode
。 GetHashCode
实现必须为比较相等的元素生成相同的代码。这不会发生在这里,因为相关比较是自定义的,而不会相应地生成哈希码。
要完成这项工作,您需要做以下两件事之一:
让比较器接受哈希码实现作为附加参数,即x => x.ID.GetHashCode()
并转发给它。这是最简单的,你应该在实践中做些什么。
修改GetHashCode
,使其成为参与比较的属性(这里是ID
属性)的哈希码的聚合函数 - a单个哈希码的直接xor可以工作(即使它可能不是optiomal)。
这会让你遇到如何检测哪个问题
属性进行比较。为了能够自动回答该问题,您需要接受表达式树而不是用于比较的委托,即Expression<Func<T, T, bool>>
,然后访问表达式树以确定要执行的操作。这一定不容易。