参照:
优秀博文:《聊一聊C#的Equals()和GetHashCode()方法》
官方文档:《Object.GetHashCode Method》
一、Object.Equals
Object.Equals
是用来比较两个对象是否相等的,所以它可以表达对象的唯一性,.net中需要比较两个对象是否相等时就是调用的这个方法。
对于值类型(如:int、double、DateTime、枚举、结构体等),系统是比较彼此内存中存放的数据是否相等来判别两个对象是否相等的,
看下面实例:
public struct Point
{
public double X;
public double Y;
public double Z;
public Point(double x, double y, double z)
{
X = x;
Y = y;
Z = z;
}
}
class Program
{
static void Main(string[] args)
{
var s = new Point(0.12, 0.15, 0);
var s2 = new Point(0.12, 0.15, 0);
//输出: true,结构体是值类型,比较的是存储的字节内容
Console.WriteLine(s.Equals(s2));
}
}
对于引用类型,系统是比较这两个对象是否存储在同一个位置来判别它们是否相等的。
注意:
string类型虽然是引用类型,但是系统已经重写了Equals方法,所以string的Equals具有实际的意义(系统还重载了==和!=运算符)。
c#允许我们重写Equals方法,这样,我们就可以根据自己的业务需要去定制了,比如下面的类:
//我们仅根据Id去就可以判断Person是否相等。
public class Person
{
public int Id {set;get;}
public string Name {set;get;}
public bool override Equals(object obj)
{
return obj is Person p && p.Id==Id;
}
}
二、Object.GetHashCode
这个方法是用来获取一个对象的hash值(一个整数)的。
当我们把对象存储在基于哈希算法的容器中(比如:Dictionary,Hashtable)时,就需要先计算对象的hashcode以给这个对象快速安排位置。
注意:HashCode不能代表对象的唯一性,但比较好的HashCode算法能最大程度上减少哈希碰撞。
三、Object.Equals和Object.GetHashCode的关系
这两个方法在系统中的定位是:Equals是用来比较两个对象是否等价的,而GetHashCode是尽最大努力区分不等价的对象的,基于此,有了下面的两个约定:
- 两个对象的用Equals比较是相等的,那么它们计算出来的HashCode必定是相等的;
- 两个不相等的对象得出的HashCode有可能是相等的,不过,我们在重写GetHashCode方法时,应尽量让它们不相等;
基于上面两条规律,我们应该明白:为什么每次重写Equals方法时,vs都提示我们重写GetHashCode方法。
另外,由于HashCode仅仅是用来存储时用来给不同的对象快速定位的,所以HashCode不具有持久性,也就是说,程序再运行一次,得到的HashCode值是不需要保持一致的,所以,不要将HashCode存储到数据库,也不要再不同的程序间传递HashCode值。