【问题标题】:Equals and GetHashCode confusionEquals 和 GetHashCode 混淆
【发布时间】:2013-11-07 06:44:23
【问题描述】:

我正在尝试实现一个不可变的Point 类,如果两个Point 实例具有相同的Coordinates,则它们被视为相等。我正在使用 Jon Skeet 的 implementation Coordinate 值类型。

为了比较Points 的相等性,我还继承了EqualityComparer<Point>IEquatable<Point>,并且我有一个单元测试如下:

Point.cs:

public class Point : EqualityCompararer<Point>, IEquatable<Point>
{
    public Coordinate Coordinate { get; private set; }

    // EqualityCompararer<Point>, IEquatable<Point> methods and other methods
}

PointTests.cs:

[Fact]
public void PointReferencesToSamePortalAreNotEqual()
{
    var point1 = new Point(22.0, 24.0);
    var point2 = new Point(22.0, 24.0);

    // Value equality should return true
    Assert.Equal(point1, point2);

    // Reference equality should return false
    Assert.False(point1 == point2);
}

现在我真的被我必须实现的 3 种接口/抽象方法弄糊涂了。它们是:

  • IEquatable&lt;Point&gt;.Equals(Point other)
  • EqualityComparer&lt;Point&gt;.Equals(Point x, Point y)
  • EqualityComparer&lt;Point&gt;.GetHashCode(Point obj)

而且由于我已经覆盖了IEquatable&lt;Point&gt;.Equals,根据MSDN,我还必须实现:

  • Object.Equals(object obj)
  • Object.GetHashCode(object obj)

现在我对满足我的单元测试所需的所有EqualsGetHashCode 方法感到非常困惑(对于point1point2,引用相等应该返回false,值相等应该返回true)。

谁能进一步解释一下EqualsGetHashCode

【问题讨论】:

  • 解释关系的简单方法:如果a.Equals(b) == true然后a.GetHashCode() == b.GetHashCode(),如果a.Equals(b) == false然后a.GetHashCode() == b.GetHashCode() || a.GetHashCode() != b.GetHashCode()
  • 这个我明白,但我的问题是为什么接口/抽象类?我应该如何实施它们以使其保持一致?
  • 您不需要实现IEqualityComparer,这只是为了将外部类作为特殊情况比较器传入。一个很好的例子:various string comparers 用于忽略大小写之类的事情。 IEquatable 是这样,你不需要将你的结构装箱在 object 中进行比较,如果你使用的是类而不是结构,你也不需要 IEquatable。
  • @ScottChamberlain:我实现了EqualityComparer&lt;T&gt;,因为我在其他使用Point 的类中使用了集合(例如,当我调用IEnuermable&lt;Point&gt;.Distinct() 时,它将使用我的比较器而不是默认的比较器)
  • 您所做的就是让默认值按照您想要的方式运行。 EqualityComparer 仅在您想要非默认行为进行比较时使用。

标签: c# .net


【解决方案1】:

因为 Coordinate 已经为您实现了 GetHashCode()Equals(Coordinate) 这实际上很容易,只需使用底层实现

public class Point : IEquatable<Point>
{
    public Coordinate Coordinate { get; private set; }

    public override int GetHashCode()
    {
        return Coordinate.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        return this.Equals(obj as Point);
    }

    public bool Equals(Point point)
    {
        if(point == null)
            return false;

        return this.Coordinate.Equals(point.Coordinate);
    }
}

IEquatable&lt;Point&gt; 是不必要的,因为它所做的只是为您节省了额外的演员表。主要是针对struct类型的类,防止将struct装箱到object传入bool Equals(object)

【讨论】:

  • 但是,当我有一个 IEnumerable&lt;Point&gt; 并在其上调用 Distinct 时,它会返回 Coordinates 相等的重复元素。在这种情况下我需要使用EqualityComparer&lt;Point&gt;吗?
  • 没关系。我自己想通了。你说的对。接受为答案。
【解决方案2】:

Equals: 用于检查两个对象是否相等。有几个相等性检查(按值,按引用),您真的想看看链接以了解它们是如何工作的,以及当您不知道谁在如何覆盖它们时的陷阱。

GetHashCode:
哈希码是一个数值,用于在基于哈希的集合(例如 Dictionary 类、Hashtable 类或从 DictionaryBase 类派生的类型)中插入和标识对象。 GetHashCode 方法为需要快速检查对象相等性的算法提供此哈希码。

假设您有两个巨大的对象,里面有很多对象,比较它们可能需要很长时间。然后你有这些对象的集合,你需要比较它们。正如定义所说,如果您不想比较两个对象,GetHashCode 将返回一个可以比较的简单数字。 (假设您正确实现了它们,两个不同的对象将不会具有相同的哈希码,而应该“相等”的对象将具有)。

如果你想要 Jon Skeet 对类似事情的看法,请查看 here

【讨论】:

    猜你喜欢
    • 2019-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-16
    • 2012-01-26
    • 2012-03-20
    相关资源
    最近更新 更多