List.Contains与自定义struct参数

时间:2016-04-28 00:40:04

标签: c# struct collections value-type

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

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

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

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

这里到底发生了什么?

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

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

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

                    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变量,也会触及continue。我不确定它可以做什么。我的等于覆盖仅检查X和Y是否相等,如果是则返回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));
    }

问题仍然存在。

3 个答案:

答案 0 :(得分:1)

Equals方法中有一个拼写错误:

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

错误的代码会将thisthis进行比较,因此它始终返回true

答案 1 :(得分:1)

好的,我相信我找出了你的问题。

您的等于覆盖不是覆盖,您可以在代码中将其作为:

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

你在那里做了什么,增加了一个名为Equals的方法。因此,您实际上已经重载了需要覆盖的实际等于方法。 Contains不会调用你的equals方法,因为它会调用带有对象的原始方法。

当你覆盖正确的equals方法时,你应该在实践中实现GetHashCode并使用GetHashCode来确定对象是否真正相等。

在你的情况下你不会有一个问题没有覆盖GetHashCode,因为你在IntVector2的另一个副本中基于两个整数相同的平均值,并且你不能真正计算它的整数哈希码作为X和Y都是整数。如果你在这里做了一个GetHashCode实现,你可能会在以后遇到bug,如果你有大量的bug,你最终可能会得到不相等的对象的dupe哈希码。

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

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

答案 2 :(得分:-1)

使用当前代码,Contains无法确定两个结构实例的相等性。如果重写IntVector2 :: GetHashCode,以便相同的值返回相同的哈希值,它应该按预期开始工作。