C#XNA:字典的麻烦

C#XNA:字典的麻烦,c#,dictionary,xna,assert,iequatable,C#,Dictionary,Xna,Assert,Iequatable,我是C#的新手。也许我没有正确地实现IEquatable,因为我的类型的对象应该被认为是相同的,而不是相同的 班级: class CompPoint : IComparable { public int X; public int Y; public CompPoint(int X, int Y) { this.X = X; this.Y = Y; } public over

我是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的
CompPoint
比这更能证明它是一个类。)

然后,该测试失败:

    [TestMethod()]
    public void compPointTest() {
        Assert.AreEqual(new CompPoint(0, 0), new CompPoint(0, 0));
    }
    [TestMethod()]
    public void hashCodeTest() {
                int x = 0;
                int y = 0;
                Assert.AreEqual(new CompPoint(x, y).GetHashCode(), new CompPoint(x, y).GetHashCode());    
    }
我误解了什么?
Assert.AreEqual()
是否使用引用相等?
CompPoint
中的
Equals()
函数是否出错

此功能也会失败:

    public void EqualsTest() {
        Assert.IsTrue(new CompPoint(1, 1).Equals(new CompPoint(1, 1)));
    }
这是因为我使用的是
词典
,它没有按照我希望的方式工作:

    [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);
    }
奇怪的是,这项测试仍然失败:

   [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);
    }

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

我认为
Assert.AreEqual
只是使用
对象。Equals
,而不是
IEquatable.Equals
。因此,您需要重写
Equals
,以反映
IEquatable.Equals
的逻辑

或者您也可以使用
Assert.IsTrue

IEquatable<CompPoint> p1 = new CompPoint(0, 0);
IEquatable<CompPoint> p2 = new CompPoint(0, 0);
Assert.IsTrue(p1.Equals(p2));
IEquatable p1=新的补偿点(0,0);
IEquatable p2=新的补偿点(0,0);
断言.IsTrue(p1.Equals(p2));
注意,我将p1和p2声明为
IEquatable
:这是为了确保调用
IEquatable.Equals
,而不是
Object.Equals
,因为接口是显式实现的


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

如果您要覆盖
Equals
,那么您还应该覆盖
GetHashCode
,因为字典将首先使用它来确定两个键是否匹配。(被认为相等的任何两个相同类型的对象都应该从
GetHashCode
返回相同的值)

公共类CompPoint:IEquatable
{
// ...
公共覆盖布尔等于(对象obj)//对象
{
返回此.Equals(obj作为ComPoint);
}
public bool Equals(CompPoint other)//IEquatable
{
return!object.ReferenceEquals(其他,null)
&&此.X等于(其他.X)
&&此.Y等于(其他.Y);
}
public override int GetHashCode()//对象
{
int hash=5419;
hash=(hash*73)+this.X.GetHashCode();
hash=(hash*73)+this.Y.GetHashCode();
返回散列;
}
}

+1。把我揍一顿。但是,与其让
Equals()
复制逻辑,不如让它调用另一个方法。稍微更新了我的问题。使用
IEquatable
作为类型而不仅仅是
CompPoint
是否重要?这很重要,因为您明确地实现了
IEquatable
。然而,我不明白为什么当你使用你的类型作为字典键时它不起作用:这很有趣,但最终没有结果。
字典
仍然无法检测到重复项。我认为
getHashCode()
可能是导致问题的原因。(见上文)不知道您是否已修复此问题,但如果您的GetHashCode方法仍然是您在上述代码中发布的方法,则由于它们调用base,它仍会为两个实例(即两个新的CompPoint(0,0))生成不同的has。GetHashCode()@Rosarch:您对
base的调用。GetHashCode
是问题所在。
GetHashCode
的默认实现将为引用类型的不同实例返回不同的hashcode,即使这些实例包含相同的数据。您正在使用默认的hashcode作为您自己实现的“种子”,因此您的方法也将为不同的实例返回不同的hashcode。
IEquatable<CompPoint> p1 = new CompPoint(0, 0);
IEquatable<CompPoint> p2 = new CompPoint(0, 0);
Assert.IsTrue(p1.Equals(p2));
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;
    }
}