List.Contains 自定义结构参数未按预期工作

List.Contains not working as expected with custom struct argument

我有一个结构 IntVector2,它有一个 X 和 Y 属性。 + 运算符被

覆盖
public static IntVector2 operator +(IntVector2 value1, IntVector2 value2)
{
    value1.X += value2.X;
    value1.Y += value2.Y;
    return value1;
}

在带有 contains 方法的列表中使用它时,它不会检查加法的总值,而只是检查变量 "current"

if (visited.Contains(current + dir))
    continue;

这里到底发生了什么?

编辑:这是变量值的屏幕截图,以及一个变量声明,它等于我期望要检查的包含值。

https://dl.dropboxusercontent.com/u/30062610/Brokestuff.png

Edit2:这是该方法的完整代码,它是 A* 寻路算法从起始向量找到结束向量的开始。

                    public Path Pathfind(IntVector2 start, IntVector2 end)
    {
        Queue<IntVector2> fillQueue = new Queue<IntVector2>();
        List<IntVector2> visited = new List<IntVector2>();
        fillQueue.Enqueue(start);
        IntVector2 current;
        while (fillQueue.Count > 0)
        {
            current = fillQueue.Dequeue();
            foreach (IntVector2 dir in Directions)
            {
                if (GetCell(current + dir).IsWall)
                    continue;
                else
                {
                    IntVector2 newstuff = current + dir;
                    if (visited.Contains(current + dir))
                        continue;
                    if ((current + dir) == end)
                    {
                        //We've reached the target, traceback the path and return it.
                    }
                    visited.Add(current);
                    fillQueue.Enqueue(current + dir);
                }
            }
        }
        return null;
    }

编辑 3:即使使用与开始时具有不同值的 newstuff 变量也会继续。我不确定它能做什么。我的 equals override 只是检查 X 和 Y 是否都相等,如果是 returns true。

下面是完整的 IntVector2 代码:http://pastebin.com/ic108SeF

编辑 4:我将 + 运算符修改为:

        public static IntVector2 operator +(IntVector2 value1, IntVector2 value2)
    {
        return new IntVector2((value1.X + value2.X), (value1.Y + value2.Y));
    }

问题依然存在。

使用您当前的代码,Contains 无法确定两个结构实例是否相等。如果您覆盖 IntVector2::GetHashCode 以便相同的值 return 具有相同的哈希值,它应该会按您预期的那样开始工作。

您在 Equals 方法中有错别字:

public override bool Equals(object obj)
{ 
    if (obj is IntVector2)
    {
        return Equals((IntVector2)this); // <-- "this" should be "obj"
    }
}

错误代码比较thisthis,所以总是returnstrue.

好的,我想我已经解决了你的问题。

你的 equals 覆盖不是覆盖,你的代码中有它:

    public bool Equals(IntVector2 other) { 
        return (X == other.X) && (Y == other.Y); 
    }

您所做的是添加一个名为 Equals 的方法。因此,您实际上已经重载了需要重写的 Actual equals 方法。 Contains 不会调用您的 equals 方法,因为它会调用带有对象的原始方法。

当您重写正确的 equals 方法时,在良好的实践中,您应该实现 GetHashCode 并使用 GetHashCode 来确定对象是否真正相等。

在你的情况下,你不会有不重写 GetHashCode 的问题,因为你是基于两个整数的相等性在 IntVector2 的另一个副本中是相同的,并且你不能真正计算出整数哈希码因为 X 和 Y 都是整数。如果您在此处执行了 GetHashCode 实现,您以后可能会 运行 发现错误,如果您有大量此类错误,您最终可能会得到不相等对象的重复哈希码。

这是您应该尝试的更新代码。

public struct IntVector2
{
    public int X { get; set; }
    public int Y { get; set; }

    public static IntVector2 operator +(IntVector2 value1, IntVector2 value2)
    {
        value1.X += value2.X;
        value1.Y += value2.Y;
        return value1;
    }

    public override int GetHashCode()
    {
        //overrode this to get rid of warning
        return base.GetHashCode();
    }

    //This equals get's called, notice the override keyword
    public override bool Equals(object obj)
    {
        if (obj is IntVector2)
        {
            IntVector2 vObj = (IntVector2)obj;
            return vObj.X == this.X && vObj.Y == this.Y;           
        }
        return false;
    }

    //This won't get called, it's not part of the framework, this is adding a new overload for equals that .Net won't know about.
    public bool Equals(IntVector2 other)
    {
        return (X == other.X) && (Y == other.Y);
    }

    public override string ToString()
    {
        return string.Format("{ value1: {0}, value2: {0} }", X, Y);
    }
}