2

我是 C# 的新手。也许我没有IEquatable正确实现,因为我的类型的对象应该被认为是相同的。

班上:

class CompPoint : IComparable {
        public int X;
        public int Y;

        public CompPoint(int X, int Y) {
            this.X = X;
            this.Y = Y;
        }

   public override bool Equals(Object o) {
        if (!(o is CompPoint)) {
            throw new ArgumentException(String.Format("argument is not a CompPoint (%s given)", o));
        }
        CompPoint cp = (CompPoint)o;

        return this.X == cp.X && this.Y == cp.Y;
    }

    public override int GetHashCode() {
        int hash = base.GetHashCode(); // this is a problem. replace with a constant?
        hash = (hash * 73) + this.X.GetHashCode();
        hash = (hash * 73) + this.Y.GetHashCode();
        return hash;
    }
}

(除了这之外,还有更多的CompPoint东西可以证明它是一个类。)

然后,此测试失败:

    [TestMethod()]
    public void compPointTest() {
        Assert.AreEqual(new CompPoint(0, 0), new CompPoint(0, 0));
    }

我有什么误解?是否Assert.AreEqual()使用参照平等?我的Equals()功能有问题CompPoint吗?

此功能也失败:

    public void EqualsTest() {
        Assert.IsTrue(new CompPoint(1, 1).Equals(new CompPoint(1, 1)));
    }

这样做的原因是我正在使用 a Dictionary,并且它没有按照我希望的方式工作:

    [TestMethod()]
    public void dictCompPointTest() {
        IDictionary<CompPoint, int> dict = new Dictionary<CompPoint, int>();
        dict[new CompPoint(0, 0)] = 4;
        dict[new CompPoint(0, 0)] = 24;
        dict[new CompPoint(0, 0)] = 31;

        Assert.AreEqual(31, dict[new CompPoint(0, 0)]);
        Assert.AreEqual(1, dict.Count);
    }

测试失败并显示以下消息:

测试方法 ShipAILabTest.BoardUtilsTest.dictCompPointTest 抛出异常:System.Collections.Generic.KeyNotFoundException:字典中不存在给定的键。

这个测试概括了我的期望。我希望由于密钥每次都相同,因此该值将被覆盖。Dictionary测试相等性的用途是什么?

更新:根据 Thomas 的建议,我添加了一个相等函数,现在CompPoint比较测试有效,并且dictCompPointTest有效。

    public override bool Equals(Object o) {
        if (!(o is CompPoint)) {
            throw new ArgumentException(String.Format("argument is not a CompPoint (%s given)", o));
        }
        CompPoint cp = (CompPoint)o;

        return this.X == cp.X && this.Y == cp.Y;
    }

奇怪的是,这个测试仍然失败:

   [TestMethod()]
    public void dictCPTest2() {
        IDictionary<CompPoint, int> dict = new Dictionary<CompPoint, int>();
        dict[new CompPoint(2, 2)] = 2;
        dict[new CompPoint(2, 2)] = 2;

        Assert.AreEqual(1, dict.Count);
    }

当键是时测试也会失败,但当键是new CompPoint(4, 1)时不会new CompPoint(0, 1)。为什么这可能适用于某些价值观而不适用于其他价值观?

更神秘的是:哈希码函数似乎工作得很糟糕。此测试失败:

    [TestMethod()]
    public void hashCodeTest() {
                int x = 0;
                int y = 0;
                Assert.AreEqual(new CompPoint(x, y).GetHashCode(), new CompPoint(x, y).GetHashCode());    
    }

上面列出了哈希码函数。这里有什么问题?这两个CompPoint对象不应该具有相同的哈希码吗?也许我的电话base.getHashCode()有问题?

4

2 回答 2

3

我认为Assert.AreEqual只是使用Object.Equals,而不是IEquatable<T>.Equals。所以你需要重写Equals以反映IEquatable<T>.Equals.

或者你也可以使用Assert.IsTrue

IEquatable<CompPoint> p1 = new CompPoint(0, 0);
IEquatable<CompPoint> p2 = new CompPoint(0, 0);
Assert.IsTrue(p1.Equals(p2));

请注意,我将 p1 和 p2 声明为IEquatable<CompPoint>: this 它以确保IEquatable<CompPoint>.Equals调用而不是Object.Equals,因为接口是显式实现的

编辑:顺便说一句,您可能想要声明CompPoint为结构而不是类。这样,您甚至不必实现任何东西,因为值类型是根据它们的字段值进行比较的

于 2010-02-07T23:35:28.553 回答
1

如果您要覆盖,Equals那么您还应该覆盖GetHashCode,因为这是字典在第一个实例中用来确定两个键是否匹配的内容。(任何两个被认为相等的相同类型的对象都应该从 . 中返回相同的值GetHashCode。)

public class CompPoint : IEquatable<CompPoint>
{
    // ...

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

    public bool Equals(CompPoint other)    // IEquatable<ComPoint>
    {
        return !object.ReferenceEquals(other, null)
            && this.X.Equals(other.X)
            && this.Y.Equals(other.Y);
    }

    public override int GetHashCode()    // object
    {
        int hash = 5419;
        hash = (hash * 73) + this.X.GetHashCode();
        hash = (hash * 73) + this.Y.GetHashCode();
        return hash;
    }
}
于 2010-02-08T00:17:41.487 回答