我无法覆盖GetHashCode()
方法和Equals()
方法。
public class Coordinate
{
int x;
int y;
public Coordinate(int p,int q)
{
this.x = p ;
this.y = q;
}
}
假设我创建了两个具有相同x和y坐标的坐标点对象。
我希望我的程序能够理解它们是平等的。
Coordinate Point 1 = new Coordinate(0,0);
Coordinate Point 2 = new Coordinate(0,0);
默认情况下,他们按预期提供不同的GetHashCode()
。
我希望它们通过覆盖它来提供相同的哈希代码,然后使用该哈希代码作为Key从Dictionary生成值。在搜索之后,我知道我还必须覆盖Equals()
。
答案 0 :(得分:0)
您必须覆盖Equals()
,因为如果两个对象具有相同的哈希码,则并不意味着它们被视为相等。哈希码只是作为一个“索引”来加速搜索。
每次使用new
时,都会创建一个实例,它与另一个实例不是同一个实例。这就是ReferenceEquals()
检查 - 想象两瓶相同的苏打水 - 它们是相同的,但它们不是相同的瓶。
Equals()
旨在检查你(开发人员)是否要将两个实例视为相等,即使它们不是同一个实例。
答案 1 :(得分:0)
你可以用这种方式实现一些东西:
public override bool Equal(Object o) {
if (object.ReferenceEquals(o, this))
return true;
Coordinate other = o as Coordinate;
else if (null == other)
return false;
return x == other.x && y == other.y;
}
public override int GetHashCode() {
return x.GetHashCode() ^ y.GetHashCode();
}
其中Equals
返回true
当且仅当实例相等而GetHashCode()
执行快速估算(如果实例具有不同的哈希码,则实例不相等但是,相反的情况并非如此)并且尽可能确保散列的均匀分布(因此在Dictionary
和类似的结构中,每个键的值大致相等)
https://msdn.microsoft.com/en-us/library/336aedhh(v=vs.100).aspx
https://msdn.microsoft.com/en-us/library/system.object.gethashcode(v=vs.110).aspx
答案 2 :(得分:0)
我会覆盖这样的命名方法。对于GetHashCode
方法,我从this question中选择了其中一个选项,但如果您愿意,可以选择其他选项。
我还将类更改为不可变。您应该只使用不可变属性/字段来计算哈希码。
public class Coordinate {
public Coordinate(int p, int q) {
x = p;
y = q;
}
private readonly int x;
private readonly int y;
public int X { get { return x; } }
public int Y { get { return y; } }
public override int GetHashCode() {
unchecked // Overflow is fine, just wrap
{
int hash = (int) 2166136261;
// Suitable nullity checks etc, of course :)
hash = (hash * 16777619) ^ x.GetHashCode();
hash = (hash * 16777619) ^ y.GetHashCode();
return hash;
}
}
public override bool Equals(object obj) {
if (obj == null)
return false;
var otherCoordinate = obj as Coordinate;
if (otherCoordinate == null)
return false;
return
this.X == otherCoordinate.X &&
this.Y == otherCoordinate.Y;
}
}
答案 3 :(得分:0)
当您拥有不可变对象时,通常会发生您尝试做的事情,无论如何,如果您不想使用struct
,您可以这样做:
public class Coord : IEquatable<Coord>
{
public Coord(int x, int y)
{
this.X = x;
this.Y = y;
}
public int X { get; }
public int Y { get; }
public override int GetHashCode()
{
object.Equals("a", "b");
// Just pick numbers that are prime between them
int hash = 17;
hash = hash * 23 + this.X.GetHashCode();
hash = hash * 23 + this.Y.GetHashCode();
return hash;
}
public override bool Equals(object obj)
{
var casted = obj as Coord;
if (object.ReferenceEquals(this, casted))
{
return true;
}
return this.Equals(casted);
}
public static bool operator !=(Coord first, Coord second)
{
return !(first == second);
}
public static bool operator ==(Coord first, Coord second)
{
if (object.ReferenceEquals(second, null))
{
if (object.ReferenceEquals(first, null))
{
return true;
}
return false;
}
return first.Equals(second);
}
public bool Equals(Coord other)
{
if (object.ReferenceEquals(other, null))
{
return false;
}
return object.ReferenceEquals(this, other) || (this.X.Equals(other.X) && this.Y.Equals(other.Y));
}
}
注意。如果您使用自定义相等,那么真的应该使您的类不可变,因为如果您使用基于哈希的集合,它可能会破坏您的代码。
我认为,当您想要像您一样进行自定义相等检查时,执行所有这些重载被认为是一种好习惯。特别是当object.GetHashCode()
为两个对象返回相同的值时,Dictionary
和其他基于散列的集合使用使用object.Equals
的默认相等运算符。
Object.ReferenceEquals(Ob,Ob)
确定引用相等,a.k.a如果两个引用指向相同的分配值,则两个引用相等,确保它是完全相同的对象。
Object.Equals(Ob)
是object
类中的虚拟方法,默认情况下它会像Object.ReferenceEquals(Ob,Ob)
Object.Equals(Ob,Ob)
调用Ob.Equals(Ob)
,所以是的,只是在IIRC之前检查null的静态速记。
答案 4 :(得分:0)
这是一个简单的方法。
首先,将类的ToString()
方法覆盖为:
public override string ToString()
{
return string.Format("[{0}, {1}]", this.x, this.y);
}
现在您可以轻松覆盖GetHashCode()
和Equals()
,如下所示:
public override int GetHashCode()
{
return this.ToString().GetHashCode();
}
public override bool Equals(object obj)
{
return obj.ToString() == this.ToString();
}
现在,如果你试试这个:
Coordinate p1 = new Coordinate(5, 0);
Coordinate p2 = new Coordinate(5, 0);
Console.WriteLine(p1.Equals(p2));
你会得到:
真