C# List.Contains在自定义结构参数中无法正常工作
我有一个结构IntVector2,它有X和Y属性。+运算符被替换为C# List.Contains在自定义结构参数中无法正常工作,c#,struct,collections,value-type,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方法时,它不会检查加法的总值,只检查变量“current” 这里到底发生了什么 编辑:这里有一个变量值的
public static IntVector2 operator +(IntVector2 value1, IntVector2 value2)
{
value1.X += value2.X;
value1.Y += value2.Y;
return value1;
}
在列表中使用contains方法时,它不会检查加法的总值,只检查变量“current”
这里到底发生了什么
编辑:这里有一个变量值的屏幕截图,以及一个变量声明,它等于我希望检查的contains值
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;
}
问题仍然存在。对于当前代码,Contains无法确定两个结构实例的相等性。如果您重写IntVector2::GetHashCode,以便相同的值返回相同的哈希值,那么它应该按照您的预期开始工作 您在
Equals
方法中有输入错误:
public override bool Equals(object obj)
{
if (obj is IntVector2)
{
return Equals((IntVector2)this); // <-- "this" should be "obj"
}
}
public override bool Equals(对象对象对象)
{
if(obj为IntVector2)
{
返回等于((IntVector2)this);//好的,我想我解决了你的问题
您的equals替代不是替代,您在代码中的替代形式为:
public bool Equals(IntVector2 other) {
return (X == other.X) && (Y == other.Y);
}
您在那里所做的是添加了一个名为Equals的方法。因此,实际上您已经重载了需要重写的实际Equals方法。Contains不会调用您的Equals方法,因为它调用了接受对象的原始方法
当您重写right equals方法时,在良好的实践中,您应该实现GetHashCode并使用GetHashCode来确定对象是否真正相等
在您的情况下,不重写GetHashCode不会有任何问题,因为您是基于IntVector2的另一个副本中相同的两个整数来计算eqaulity的,并且您不能真正为此计算整数哈希代码,因为X和Y都是整数。如果您在这里执行GetHashCode实现,如果您有一个较大的nu,您可能会在以后遇到错误其中的一些可能会导致重复哈希代码,这些代码是不相等的对象
以下是您应该尝试的更新代码
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);
}
}
您为什么要修改value1
?您是否更改了Equals
定义?((1,1)+(2,2))。Equals(3,3)
为我生成true
。我想用第二个参数的值修改第一个参数是可行的。我是否应该将其更改为返回一个新的IntVector2和新的总计,而不是修改第一个参数?@user3010006然后在那里放置一个断点并对其进行调试-因为它确实适用于默认的Equals
实现另外,请向我们展示currentDir
,dir
的值,以及您希望在visted
@user3010006中看到的内容。如果我们都看过了,代码肯定会起作用。我想visted中的实际内容与您的预期不符。List
不使用GetHashCode
.List可能没有,但是Object.Equals有,并且List::Contain使用Object.Equals,除非提供了可选的比较器。不幸的是,这是不正确的。如果您不确信,您可以在Equals
上设置断点。默认的对象.Equals
使用对象。ReferenceEquals
我想知道了,现在就尝试。谢谢!Also你的方法名是contains而不是equals。但我得到了:3Ah我走错了pastebin链接,我看到了另一个,但这个输入错误也在那里。谢谢你。我希望我能把你们两个都标记正确!我的帐户也无法向上投票(不过这很好!@user3010006:您应该在您的结构上实现IEquatable
接口,以便包含调用等于(IntVector2 other)
直接重载,而不必对值进行装箱和取消装箱。
public bool Equals(IntVector2 other) {
return (X == other.X) && (Y == other.Y);
}
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);
}
}