请问,如何重写GetHashCode方法

dtvsdrct4 2011-10-24 05:33:27
通过阅读一些资料,基本理解这么几点:
1.如果两个对象的GetHashCode()不一样,他们的Equals()方法结果就不能为true.
2.如果GetHashCode两个对象相同,这也不是equals的充分条件,然后调equals方法看他们是否满足equals里的逻辑
才是两个对象相等的充分条件.

问题:
1:既然GetHashCode是针对任何对象,生成一个Int32类型的散列码。既然是生成的,那你怎么能控制两个对象的GetHashCode()一样
2:比如,写IEqualityComparer接口的实现类的时候,要制作自定义的两个引用类型对象比较器,重写Equals 方法之后,怎么重写GetHashCode方法,使得两个对象的返回的哈代码一样。

看了很久,不明白,怎么重写GetHashCode方法
...全文
521 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
阿非 2011-10-25
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 dtvsdrct4 的回复:]
第二点,重写hGetHashCode的时候,如何使得HashCode值一致呢?
[/Quote]
难道制定的规则对同一实例会有不同结果么?

public int GetHashCode(List<string> obj)
{
if (obj == null)
return 0;

int hash = 17;
hash = (hash * 3) + obj.Count.GetHashCode();
foreach (string str in obj)
{
hash = (hash * 3) + str.GetHashCode();
}
return hash;
//throw new NotImplementedException();
}

dtvsdrct4 2011-10-24
  • 打赏
  • 举报
回复
感谢,caozhy,我还是写自己的判断去了,明天再来看一下
threenewbee 2011-10-24
  • 打赏
  • 举报
回复
不光是lz,很多这里讨论的人,首先就不懂什么是hash,而hash这样的概念,在数据结构中都会讲到。

先理解了hash,再理解hash算法,再理解.NET里面的GetHashCode。

“数据结构中的散列不记得?一般是要质数的”这种驴唇不对马嘴的话就不会冒出来了。
threenewbee 2011-10-24
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 dtvsdrct4 的回复:]
引用 13 楼 caozhy 的回复:

这个问题,我在http://topic.csdn.net/u/20111024/21/be44a7d1-2eda-4905-8295-73f8bc17ab5b.html回答你了。

GetHashCode一般没有必要自己写。尽量利用现有代码的GetHashCode

思路,相同的string的HashCode是相等的,相等的值类型也相等。所以,……
[/Quote]

首先,你对C#语言不熟悉,函数调用怎么回事都没理解。。。
xiongxyt2 2011-10-24
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 dtvsdrct4 的回复:]
引用 5 楼 findcaiyzh 的回复:

一些例子

http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode

完了,完了,看不懂
int hash = 17;
hash = hash * 23 + fi……
[/Quote]
数据结构中的散列不记得?一般是要质数的
dtvsdrct4 2011-10-24
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 fangxinggood 的回复:]

return obj.ToString().GetHashCode();

如果重写了ToString()比如Person.ToString()返回的是ID,那么才有意义。

否则直接返回类名,那么这个类实例equals都相等了。
[/Quote]
如果我么有写自定义的Person类,而类型参数是List<sting>的,那又怎么写?还是写ID ?
机器人 2011-10-24
  • 打赏
  • 举报
回复
return obj.ToString().GetHashCode();

如果重写了ToString()比如Person.ToString()返回的是ID,那么才有意义。

否则直接返回类名,那么这个类实例equals都相等了。
dtvsdrct4 2011-10-24
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 caozhy 的回复:]

这个问题,我在http://topic.csdn.net/u/20111024/21/be44a7d1-2eda-4905-8295-73f8bc17ab5b.html回答你了。

GetHashCode一般没有必要自己写。尽量利用现有代码的GetHashCode

思路,相同的string的HashCode是相等的,相等的值类型也相等。所以,你要考虑的是构造一个值类型(结构体或者字符串……
[/Quote]
你说的我有点懂了,不过
public int GetHashCode(Person obj)
{
return obj.ID.GetHashCode();
}

obj不是参数吗?不同的参数,其ID值肯定是不一样的啊,怎么会返回相同的HashCode呢?
如同 return obj.ToString().GetHashCode();参数obj的字符串也肯定是不等的啊,为什么好多人都是这么写的呢?在线等
threenewbee 2011-10-24
  • 打赏
  • 举报
回复
这个问题,我在http://topic.csdn.net/u/20111024/21/be44a7d1-2eda-4905-8295-73f8bc17ab5b.html回答你了。

GetHashCode一般没有必要自己写。尽量利用现有代码的GetHashCode

思路,相同的string的HashCode是相等的,相等的值类型也相等。所以,你要考虑的是构造一个值类型(结构体或者字符串,或者简单类型),使得相等的值有唯一的表示,不等的值有不等的表示,然后调用它的 GetHashCode 即可。
dtvsdrct4 2011-10-24
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 juliohuang 的回复:]

GetHashCode
第一计算够简单,性能开销不要太大
第二两个数据Equal的时候值要一致
第三两个数据比较不Equal的时候尽可能不一致
[/Quote]
第二点,重写hGetHashCode的时候,如何使得HashCode值一致呢?
黄亮 2011-10-24
  • 打赏
  • 举报
回复
GetHashCode
第一计算够简单,性能开销不要太大
第二两个数据Equal的时候值要一致
第三两个数据比较不Equal的时候尽可能不一致
小赖赖 2011-10-24
  • 打赏
  • 举报
回复
&|在这里是按位运算符,不是布尔运算符
比如
1&2=0
1|2=3
dtvsdrct4 2011-10-24
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 skyparty 的回复:]

GetHashCode()一般不大需要重写
Equals()重写的机会更多一些

GetHashCode()重写时需要遵从2个原则
相等的2个对象,HashCode应该相等
不相等的对象,应该尽量使HashCode的值不同,或分布均匀,否则在用HashMap存放对象时,会严重影响效率

比如一个复杂类型,可以用
class Test
{
String a;
in……
[/Quote]
有布尔运算符,返回值怎么会是int型呢
小赖赖 2011-10-24
  • 打赏
  • 举报
回复
GetHashCode()一般不大需要重写
Equals()重写的机会更多一些

GetHashCode()重写时需要遵从2个原则
相等的2个对象,HashCode应该相等
不相等的对象,应该尽量使HashCode的值不同,或分布均匀,否则在用HashMap存放对象时,会严重影响效率

比如一个复杂类型,可以用
class Test
{
String a;
int b;
public int GetHashCode()
{
return a.GetHashCode()&b.GetHashCode()+a.GetHashCode()|b.GetHashCode();//随意计算
}
}
dtvsdrct4 2011-10-24
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 findcaiyzh 的回复:]

一些例子

http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode
[/Quote]
完了,完了,看不懂
int hash = 17;
hash = hash * 23 + field1.GetHashCode();
hash = hash * 23 + field2.GetHashCode();
hash = hash * 23 + field3.GetHashCode();
return hash;

为什么要这样写啊,17?23? 18不行吗,
dtvsdrct4 2011-10-24
  • 打赏
  • 举报
回复
我就是不知道怎么重写?
窗户纸 2011-10-24
  • 打赏
  • 举报
回复
缺省的Equal()和getHashCode()如果内存中实例是同一个,他才会返回true, 但实际情况不是时就需要重写。
窗户纸 2011-10-24
  • 打赏
  • 举报
回复
equal()和gethashcode()重写有很多情况,具体问题具体分析,现提供一种场景供参考。
某应用要比较学生A(假设其数据库Id=200),该对象进行过两次实例化,这时使用equal()时,两次实例化的对象比较结果肯定是false, 但实际都是A, 这样我们就需要重写equal(), 在其内部,如果ID>0,则返回ID,否则返回base值。
加载更多回复(1)
C#本质论(第3版) 详细介绍C# 4.0 第1章 c#概述 1.1 hello world 1.2 c#语法基础 1.2.1 c#关键字 1.2.2 类型定义 1.2.3 main 1.2.4 语句和语句分隔符 1.2.5 空白 1.3 使用变量 1.3.1 数据类型 1.3.2 变量的声明 1.3.3 变量的赋值 1.3.4 变量的使用 1.4 控制台输入和输出 1.4.1 从控制台获取输入 1.4.2 将输出写入控制台 1.5 注释 1.6 托管执行和公共语言基础结构 1.7 c#和net版本 .1.8 cil和ildasm 1.9 小结 第2章 数据类型 2.1 基本数值类型 2.1.1 整数类型 2.1.2 浮点类型 2.1.3 decimal类型 2.1.4 字面值 2.2 更多基本类型 2.2.1 布尔类型 2.2.2 字符类型 2.2.3 字符串 2.3 null和void 2.3.1 null 2.3.2 void 2.4 类型的分类 2.4.1 值类型 2.4.2 引用类型 2.5 可空修饰符 2.6 数据类型之间的转换 2.6.1 显式转型 2.6.2 隐式转型 2.6.3 不进行转型的类型转换 2.7 数组 2.7.1 数组的声明 2.7.2 数组的实例化和赋值 2.7.3 数组的使用 2.7.4 字符串作为数组使用 2.7.5 常见错误 2.8 小结 第3章 运算符和控制流 3.1 运算符 3.1.1 一元运算符正和负 3.1.2 二元算术运算符 3.1.3 圆括号运算符 3.1.4 赋值运算符 3.1.5 递增和递减运算符 3.1.6 常量表达式 3.2 流控制概述 3.2.1 if语句 3.2.2 嵌套if 3.3 代码块 3.4 作用域和声明空间 3.5 布尔表达式 3.5.1 关系运算符和相等性运算符 3.5.2 逻辑布尔运算符 3.5.3 逻辑求反运算符 3.5.4 条件运算符 3.5.5 空接合运算符 3.6 按位运算符 3.6.1 移位运算符 3.6.2 按位运算符 3.6.3 按位赋值运算符 3.6.4 按位取反运算符 3.7 控制流语句 3.7.1 whi.1 e和do/while循环 3.7.2 for循环 3.7.3 foreach循环 3.7.4 switch语句 3.8 跳转语句 3.8.1 break语句 3.8.2 continue语句 3.8.3 go to语句 3.9 c#预处理器指令 3.9.1 排除和包含代码 3.9.2 定义预处理器符号 3.9.3 生成错误和警告 3.9.4 关闭警告消息 3.9.5 nowarn:选项 3.9.6 指定行号 3.9.7 可视编辑器提示 3.10 小结 第4章 方法和参数 4.1 方法的调用 4.1.1 命名空间 4.1.2 类型名称 4.1.3 作用域 4.1.4 方法名称 4.1.5 参数 4.1.6 方法返回值 4.1.7 语句与方法调用的比较 4.2 方法的声明 4.2.1 参数声明 4.2.2 方法返回值声明 4.3 uslng指令 4.4 main()的返回值和参数 4.5 参数 4.5.1 值参数 4.5.2 引用参数 4.5.3 输出参数 4.5.4 参数数组 4.6 递归 4.7 方法重载 4.8 可选参数 4.9 用异常实现基本错误处理 4.9.1 捕捉错误 4.9.2 使用throw语句报告错误 4.10 小结 第5章 类 5.1 类的定义和实例化 5.2 实例字段 5.2.1 实例字段的声明 5.2.2 实例字段的访问 5.3 实例方法 5.4 使用this关键字 5.5 访问修饰符 5.6 属性 5.6.1 属性的声明 5.6.2 自动实现的属性 5.6.3 命名规范 5.6.4 提供属性验证 5.6.5 读和只写属性 5.6.6 为取值方法和赋值方法指定访问修饰符 5.6.7 属性作为虚字段使用 5.6.8 属性和方法调用不允许作为ref或out参数值使用 5.7 构造器 5.7.1 构造器的声明 5.7.2 默认构造器 5.7.3 对象初始化器 5.7.4 构造器的重载 5.7.5 使用this调用另一个构造器 5.8 静态成员 5.8.1 静态字段 5.8.2 静态方法 5.8.3 静态构造器 5.8.4 静态属性 5.8.5 静态类 5.9 扩展方法 5.10 封装数据 5.10.1
C#5.0本质论第四版,高清扫描的,对C#5.0技术讲的比较详细,第1章 C#概述 1 1.1 Hello,World 1 1.2 C#语法基础 3 1.2.1 C#关键字 3 1.2.2 标识符 4 1.2.3 类型定义 5 1.2.4 Main 6 1.2.5 语句和语句分隔符 7 1.2.6 空白 8 1.2.7 使用变量 8 1.2.8 数据类型 9 1.2.9 变量的声明 9 1.2.10 变量的赋值 10 1.2.11 变量的使用 11 1.3 控制台输入和输出 11 1.3.1 从控制台获取输入 11 1.3.2 将输出写入控制台 12 1.3.3 注释 14 1.3.4 托管执行和公共语言基础结构 16 1.3.5 C#和.NET版本 17 1.3.6 CIL和ILDASM 18 1.4 小结 20 第2章 数据类型 21 2.1 基本数值类型 21 2.1.1 整数类型 22 2.1.2 浮点类型 23 2.1.3 decimal类型 23 2.1.4 字面值 24 2.2 更多基本类型 27 2.2.1 布尔类型 27 2.2.2 字符类型 27 2.2.3 字符串 29 2.3 null和void 34 2.3.1 null 34 2.3.2 void 35 2.4 类型的分类 37 2.4.1 值类型 37 2.4.2 引用类型 37 2.5 可空修饰符 38 2.6 数据类型之间的转换 39 2.6.1 显式转型 39 2.6.2 隐式转型 41 2.6.3 不使用转型操作符的类型转换 42 2.7 数组 43 2.7.1 数组的声明 44 2.7.2 数组的实例化和赋值 45 2.7.3 数组的使用 48 2.7.4 字符串作为数组使用 52 2.7.5 常见数组错误 53 2.8 小结 55 第3章 操作符和控制流 57 3.1 操作符 57 3.1.1 一元操作符正和负 58 3.1.2 二元算术操作符 58 3.1.3 复合赋值操作符 64 3.1.4 递增和递减操作符 65 3.1.5 常量表达式和常量符号 68 3.2 控制流程概述 69 3.2.1 if语句 70 3.2.2 嵌套if 71 3.3 代码块 73 3.4 代码块、作用域和声明空间 74 3.5 布尔表达式 76 3.5.1 关系操作符和相等性操作符 77 3.5.2 逻辑布尔操作符 77 3.5.3 逻辑求反操作符 78 3.5.4 条件操作符 79 3.5.5 空接合操作符 80 3.6 按位操作符 80 3.6.1 移位操作符 81 3.6.2 按位操作符 82 3.6.3 按位赋值操作符 83 3.6.4 按位取反操作符 84 3.7 控制流语句(续) 84 3.7.1 while和do while循环 84 3.7.2 for循环 86 3.7.3 foreach循环 88 3.7.4 switch语句 90 3.8 跳转语句 92 3.8.1 break语句 92 3.8.2 continue语句 94 3.8.3 goto语句 95 3.9 C#预处理指令 97 3.9.1 排除和包含代码 98 3.9.2 定义预处理符号 98 3.9.3 生成错误和警告 99 3.9.4 关闭警告消息 99 3.9.5 nowarn:选项 99 3.9.6 指定行号 100 3.9.7 可视编辑器提示 100 3.10 小结 101 第4章 方法和参数 103 4.1 方法的调用 104 4.1.1 命名空间 105 4.1.2 类型名称 106 4.1.3 作用域 107 4.1.4 方法名称 107 4.1.5 形参和实参 107 4.1.6 方法返回值 107 4.1.7 语句与方法调用的比较 108 4.2 方法的声明 108 4.2.1 形式参数声明 109 4.2.2 方法返回类型声明 110 4.3 using指令 111 4.4 Main()的返回值和参数 114 4.5 方法的参数 116 4.5.1 值参数 116 4.5.2 引用参数(ref) 117 4.5.3 输出参数(out) 118 4.5.4 参数数组 120 4.6 递归 122 4.7 方法重载 124 4.8 可选参数 126 4.9 用异常实现基本错误处理 129 4.9.1 捕捉错误 130 4.9.2 使用throw语句报告错误 136 4.10 小结 138 第5章 类 139 5.1 类的定义和实例化 141 5.2 实例字段 144 5.2.1 实例字段的声明 144 5.2.2 实例字段的访问 144 5.3 实例方法 145 5.4 使用this关键字 146 5.5 访问修饰符 151 5.6 属性 153

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧