【问题标题】:IEqualityComparer and Linq Distinct - Hard Code GetHashCode()IEqualityComparer 和 Linq Distinct - 硬代码 GetHashCode()
【发布时间】:2014-07-16 13:45:17
【问题描述】:

我有一个 CustomObject 数组和一个自定义 IEqualityComparer<CustomObject>。我已经硬编码了IEqualityComparer.GetHashCode() 方法来返回一个常量42。

当我在数组上运行 linq 的 Distinct 方法时,没有过滤掉任何内容。有人知道为什么吗?

注意:我知道这里有很多关于这个问题的问题,但是,我见过的那些(C# Distinct on IEnumerable<T> with custom IEqualityComparer、Distinct() with lambda? 等)只是说要确保实施GetHashCode。他们都没有解释,为什么它不起作用。

代码:

public class CustomObject
{
    public string Name { get; set; }
}

public class CustomObjectEqualityComparer : IEqualityComparer<CustomObject>
{
    public bool Equals(CustomObject x, CustomObject y)
    {
        //Every CustomObject should now be 'equal'!
        return x.GetHashCode() == y.GetHashCode();
    }

    public int GetHashCode(CustomObject obj)
    {
        //Every CustomObject should now be 'equal'!
        return 42;
    }
}

测试:

[TestFixture]
public class TestRunner
{
    private CustomObject[] customObjects = 
    {
        new CustomObject {Name = "Please"},
        new CustomObject {Name = "Help"},
        new CustomObject {Name = "Me"},
        new CustomObject {Name = "Stack"},
        new CustomObject {Name = "Overflow"},
    };

    [Test]
    public void DistinctTest()
    {
        var distinctArray =
            customObjects.Distinct(new CustomObjectEqualityComparer()).ToArray();

        //Since every CustomObject is 'Equal' there should only be
        //1 element in the array.
        Assert.AreEqual(1, distinctArray.Length);
    }
}

这是我运行测试得到的输出:

 Expected: 5
 But was:  1

如果我调试测试,我可以看到 GetHashCode 正在被调用,那么为什么 Distinct 没有过滤掉所有的“重复项”?

【问题讨论】:

  • 如果相关,我使用.net 4.5.1
  • 简单,您在相等期间在CustomObject 上调用GetHashCode,而不是调用您的硬编码版本。 Distinct 实现是使用自定义比较器的。它将首先调用GetHashCode。如果发生冲突,它将调用Equals,您在CustomObject 上没有覆盖它,因此将是一个参考哈希码。
  • 但是我传递了我的CustomObjectEqualityComparer。比较应该委托给这个类,对吧?
  • 该死,在阅读 Jon Skeet 的回复后,我现在明白了,你是对的 @AdamHouldsworth。谢谢!

标签: c# .net linq linq-to-objects


【解决方案1】:

当我在数组上运行 linq 的 Distinct 方法时,没有过滤掉任何内容。有人知道为什么吗?

是的 - Equals 将为任何两个不同的对象返回 false。在您的 Equals 实现中,您正在调用 CustomObject.GetHashCode 方法(未被覆盖),不是您的自定义比较器的 GetHashCode 方法。如果您希望 Equals 调用您的自定义 GetHashCode 方法,则需要将其更改为:

public bool Equals(CustomObject x, CustomObject y)
{
    return GetHashCode(x) == GetHashCode(y);
}

或者给定GetHashCode(CustomObject)的实现,您可以将其简化为:

public bool Equals(CustomObject x, CustomObject y)
{
    return true;
}

请注意,Distinct() 调用了您的 GetHashCode 方法 ,但随后它调用了您的 Equals 方法来检查对象是否真的相等...你是说他们不是(除非有很大的巧合)。

【讨论】:

  • 是的,做到了。谢谢乔恩!
  • 作为一个附带问题,这里是否已经有一个关于为什么GetHashCode() 和Equals() 都需要由Distinct 调用的线程?我可以理解GetHashCode() 用于将对象放入HashTable,但不能Distinct 假设哈希值相等,对象是否相等?
  • @ppittle 不,它以另一种方式工作,不同哈希的两个对象 not 相等(这与声明具有相同哈希的两个对象相等略有不同)。由于散列缩小了可用值的范围,因此会发生冲突,因此随后使用Equals 来测试真正的相等性。这是一种性能/准确性的权衡,当您没有发生太多碰撞时效果很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-08
  • 2017-05-20
  • 1970-01-01
相关资源
最近更新 更多