为什么我的动态IEqualityComparer不起作用?

时间:2013-12-17 15:50:47

标签: c# linq comparison

我有一个班级

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不起作用?

1 个答案:

答案 0 :(得分:8)

因为您的相等比较器没有正确实现GetHashCodeGetHashCode实现必须为比较相等的元素生成相同的代码。这不会发生在这里,因为相关比较是自定义的,而不会相应地生成哈希码。

要完成这项工作,您需要做以下两件事之一:

  1. 让比较器接受哈希码实现作为附加参数,即x => x.ID.GetHashCode()并转发给它。这是最简单的,你应该在实践中做些什么。

  2. 修改GetHashCode,使其成为参与比较的属性(这里是ID属性)的哈希码的聚合函数 - a单个哈希码的直接xor可以工作(即使它可能不是optiomal)。

    这会让你遇到如何检测哪个问题 属性进行比较。为了能够自动回答该问题,您需要接受表达式树而不是用于比较的委托,即Expression<Func<T, T, bool>>,然后访问表达式树以确定要执行的操作。这一定不容易。