重写Equals为什么要同时重写GetHashCode
Posted 未将对象引用设置到对象的实例
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重写Equals为什么要同时重写GetHashCode相关的知识,希望对你有一定的参考价值。
.NET程序员都知道,如果我们重写一个类的Equals方法而没有重写GetHashCode,则VS会提示警告 :“***”重写 Object.Equals(object o)但不重写 Object.GetHashCode() 。
但是,为什么重写Equals一定要同时重写GetHashCode呢?
微软的解释是:
GetHashCode 基于适合哈希算法和诸如哈希表的数据结构的当前实例返回一个值。 两个相等的同类型对象必须返回相同的哈希代码,才能确保以下类型的实例正确运行:
-
HashTable
-
Dictionary
-
SortDictionary
-
SortList
-
HybredDictionary
-
实现 IEqualityComparer 的类型
链接:http://msdn.microsoft.com/zh-cn/library/vstudio/ms182358.aspx
举个例子:
重写一个Person类
public class Person { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } /// <summary> /// 重写Equals,如果Name与Age相等,就认为类相等 /// </summary> /// <param name="obj"></param> /// <returns></returns> public override bool Equals(object obj) { if (obj == null) return false; if (obj is Person) { var person = obj as Person; return person.Age == this.Age && person.Name == this.Name; } else return false; } }
写一个测试方法:
public static void Main(string[] args) { Person person1 = new Person() { Id = 1, Name = "AA", Age = 21 }; Person person2 = new Person() { Id = 2, Name = "AA", Age = 21 }; Console.WriteLine("person1与person2是否相等:" + person1.Equals(person2)); Console.Read(); }
结果:
返回的结果是true,这好像是我们的重写方法成功了。那我们继续写一个测试方法吧。
ICollection<Person> list = new HashSet<Person>(); list.Add(person1); Console.WriteLine("List是否包含person1:"+list.Contains(person1)); Console.WriteLine("List是否包含person2:" + list.Contains(person2));
结果:
这时,就出问题了。既然person1与person2相等,list它包含person1,那也应该包含person2吧。原因就是我们没有重写GetHashCode方法,相同的对象没有返回相等的HashCode。
我们重新改变一下Person,让它重写GetHashCode方法。
public class Person { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } /// <summary> /// 重写Equals,如果Name与Age相等,就认为类相等 /// </summary> /// <param name="obj"></param> /// <returns></returns> public override bool Equals(object obj) { if (obj == null) return false; if (obj is Person) { var person = obj as Person; return person.Age == this.Age && person.Name == this.Name; } else return false; } public override int GetHashCode() { return this.Name.GetHashCode()^this.Age.GetHashCode(); } }
再运行两个测试方法:
现在,方法都返回true了。
还有一个例子,如果将Person类当作键值放在字典中也会有问题,可以参见:http://book.51cto.com/art/201109/292340.htm。
重写GetHashCode的原则很简单,只要能保证两个相等的同类型对象返回相同的哈希代码就OK了。
还找到一个说得比较好的地方,里面第二个评论很精彩。http://blog.csdn.net/chenyuxu0/article/details/5886771