C# 在==运算符重写中使用GetHashCode

C# 在==运算符重写中使用GetHashCode,c#,C#,只是想知道我在标题中提到的是不是一个好的实践。这对我来说很有意义,我们重写GetHashCode以返回一个基于两个属性的值,如果这两个属性匹配,则这两个对象应被视为相等。逻辑似乎很好,代码也可以运行,但我不知道它是否会导致其他问题 这是使用GetHashCode: public static bool operator ==(CartesianCoordinates a, CartesianCoordinates b) { return a.GetHashCode() == b.GetH

只是想知道我在标题中提到的是不是一个好的实践。这对我来说很有意义,我们重写GetHashCode以返回一个基于两个属性的值,如果这两个属性匹配,则这两个对象应被视为相等。逻辑似乎很好,代码也可以运行,但我不知道它是否会导致其他问题

这是使用GetHashCode:

public static bool operator ==(CartesianCoordinates a, CartesianCoordinates b)
{
    return a.GetHashCode() == b.GetHashCode(); // Using GetHashCode here
}

public static bool operator !=(CartesianCoordinates a, CartesianCoordinates b)
{
    return !(a == b);
}

public override bool Equals(object obj)
{
    return this == (CartesianCoordinates)obj; // This just uses the == override
}

public override int GetHashCode()
{
    return (this.X + this.Y.ToLower()).GetHashCode(); // GetHashCode hashes the two properties we care about
}
我以前就是这样做的:

public static bool operator ==(CartesianCoordinates a, CartesianCoordinates b)
{
    return a.X == b.X && string.Equals(a.Y, b.Y, StringComparison.CurrentCultureIgnoreCase); // The difference is here
}

public static bool operator !=(CartesianCoordinates a, CartesianCoordinates b)
{
    return !(a == b);
}

public override bool Equals(object obj)
{
    return this == (CartesianCoordinates)obj;
}

public override int GetHashCode()
{
    return (this.X + this.Y.ToLower()).GetHashCode();
}
重要提示:

在CartesianCoordinates对象中,X是整数,Y是字符串:

public int X { get; set; }
public string Y { get; set; }
Lmk,提前谢谢

这是非常错误的。
GetHashCode()
不是唯一的

您的特定示例更糟糕,因为您的
GetHashCode()
是可交换的。

这是非常错误的。
GetHashCode()
不是唯一的


您的特定示例更糟糕,因为您的
GetHashCode()
是可交换的。

这样做不仅是错误的做法,而且是错误的!两个相等的对象必须具有相同的哈希代码,但事实并非如此:两个不同的对象可以具有相同的哈希代码(通常会)。因此,如果使用hash码来判断对象是否相等,在某些情况下,当它们实际上不同但恰好有相同的哈希代码时,您会认为它们是相等的。哈希代码不是唯一标识符


根据您的
GetHashCode
实现,坐标为
(x,y)
(y,x)
的对象将被视为相等的(因为
x+y==y+x

这样做不仅是不好的做法,而且是错误的!两个相等的对象必须具有相同的哈希代码,但事实并非如此:两个不同的对象可以具有相同的哈希代码(通常会)。因此,如果使用hash码来判断对象是否相等,在某些情况下,当它们实际上不同但恰好有相同的哈希代码时,您会认为它们是相等的。哈希代码不是唯一标识符

根据您的
GetHashCode
实现,坐标
(x,y)
(y,x)
的对象将被视为相等(因为
x+y==y+x

GetHashCode()
可以为两个不相等的
笛卡尔坐标返回相同的值,例如,对于两个对象
c1
c2
,使得
c1.x==c2.y
c1.y==c2.x

对于更复杂的对象,如果预先计算hashCode,则可以使用它来短路,但最终需要比较所有字段。这里的比较很简单

GetHashCode()
可以为两个不相等的
CartesianCoordinates
返回相同的值,例如,对于两个对象
c1
c2
,使得
c1.x==c2.y
c1.y==c2.x


对于更复杂的对象,如果预先计算hashCode,则可以使用它来短路,但最终需要比较所有字段。这里的比较很简单

您的GetHashCode将为{3,1}和{1,3}返回相同的值。我怀疑这不是故意的

如果您的GetHashCode方法返回了更好的hashcode,我仍然建议不要使用GetHashCode作为相等比较。GetHashCode契约规定具有相同跟踪属性的两个对象应生成相同的hashcode,而不是具有相同hashcode的两个对象将相等

编辑以添加:


有关更好的实现的详细信息,请参见此问题,特别是Josh Bloch/Jon Skeet的答案。

您的GetHashCode将为{3,1}和{1,3}返回相同的值。我怀疑这不是故意的

如果您的GetHashCode方法返回了更好的hashcode,我仍然建议不要使用GetHashCode作为相等比较。GetHashCode契约规定具有相同跟踪属性的两个对象应生成相同的hashcode,而不是具有相同hashcode的两个对象将相等

编辑以添加:


有关更好的实现的详细信息,请参见此问题,特别是Josh Bloch/Jon Skeet的答案。

不,使用哈希代码定义相等性不是好的做法(甚至是正确的),因为不同的对象可能具有相同的哈希代码(在String.GetHashCode的情况下肯定会发生)


在您的特定情况下,还应该注意,您的GetHashCode方法甚至与您的
Equals
方法不匹配,因为您的
GetHashCode
将为除大小写之外相等的字符串返回不同的哈希代码,而在这种情况下,您的
Equals
将返回true。

不,这不是好的做法(甚至是正确的)使用哈希代码定义相等,因为不同的对象可能具有相同的哈希代码(在String.GetHashCode的情况下肯定会发生)

在您的特定情况下,还应该注意,您的GetHashCode方法甚至与您的
Equals
方法不匹配,因为您的
GetHashCode
将为除大小写之外相等的字符串返回不同的哈希代码,而在这种情况下,
Equals
将返回true。

您的
GetHashCode()
将为
(2,4)
(4,2)
提供相同的结果。可能不是您想要的结果

GetHashCode()
通常也不是一个好的相等性测试。即使是一个真正好的哈希也只是一个32位整数。在笛卡尔平面上使用它来测试相等性将导致许多(无穷多)冲突。

您的
GetHashCode()
将为
(2,4)
(4,2)给出相同的结果
。可能不是你想要的

GetHashCode()
通常也不是一个好的相等性测试。即使是一个真正好的哈希也只是一个32位整数。使用它来测试笛卡尔平面中的相等性将导致