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"
}
}
错误代码比较this
和this
,所以总是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);
}
}
我有一个结构 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"
}
}
错误代码比较this
和this
,所以总是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);
}
}