我经常遇到重写GetHashCode需要注意事项的问题,因而,我在这里总结一下: GetHashCode的作用 设计仅用于在一个hash表中放置,索引一个对象。 从这个例子中我们能够推断出GetHashCode的规则及指南。 Rule: GetHashCode禁止抛出异常,必须要有返回值 获取哈希代码只计算一个整数;没有任何理由能让它失败。GetHashCode 的实现应该能够处理合法对象。 Guideline: GetHashCode 的实现必须非常快 hash的目的就是优化查询操作,如果调用GetHashCode消耗的时间比直接查询一万个成员更多,那么没有分毫意义。 Security issue:不要把GetHashCode用于其他用途 GetHashCode设计仅用于平衡hash表,不用用作其他用途,特别是: 没有给对象提供唯一键,碰撞几率非常高。
Equals和GetHashCode Equals每个实现都必须遵循以下约定: 自反性(Reflexive): x.equals(x)必须返回true. 非null(Non-null): 如果x不是null,y为null,则x.equals(y)必须为false GetHashCode: 两个相等对象根据equals方法比较时相等,那么这两个对象中任意一个对象的 (Student obj) { return obj.Name.GetHashCode() * obj.Age; } } 上述代码片段如果两个 Equals返回的true并且GetHashCode返回相同的哈希码,则认为两个对象相等. 重写Equals和GetHashCode var stu1 = new Student { Name = "MR.A", Age = 32 }; var stu2 = new Student { Name
Equals和GetHashCode Equals每个实现都必须遵循以下约定: 自反性(Reflexive): x.equals(x)必须返回true. 非null(Non-null): 如果x不是null,y为null,则x.equals(y)必须为false GetHashCode: 两个相等对象根据equals方法比较时相等,那么这两个对象中任意一个对象的 Equals返回的true并且GetHashCode返回相同的哈希码,则认为两个对象相等. 重写Equals和GetHashCode var stu1 = new Student { Name = "MR.A", Age = 32 }; var stu2 = new Student { Name () { return Name.GetHashCode() * Age; } } var stu1 = new Student {
GetHashCode的用处 首先声明一下,这里的GetHashCode是Object.GetHashCode,是需要在对象中定义的函数。 为什么不能使用默认的GetHashCode 直接使用默认的ValueType的GetHashCode实现容易造成哈希冲突,这样的Object在配合哈希表这类数据结构使用的时候会出现性能问题。 (); hash = hash * 23 + field2.GetHashCode(); hash = hash * 23 + field3.GetHashCode(); hash * 16777619) ^ field2.GetHashCode(); hash = (hash * 16777619) ^ field3.GetHashCode(); Object.GetHashCode Method 不要使用 struct 默认的 GetHashCode 实现 12-1怎么写HashCode HashCode.Combine Method
本文来聊聊在重写某个类的 GetHashCode 方法时,可以如何实现 GetHashCode 的返回值 按照 GetHashCode 方法的原则,要求两个对象如果 Equals 返回 true 那么一定要求 GetHashCode 也返回相同的值。 当然,反过来不成立,也就是两个对象返回的 GetHashCode 的值相同,对象可以是不相等的 实现 GetHashCode 方法的方式有很多,最简单的就是通过调用基类的 GetHashCode 方法, 代码如下 public override int GetHashCode() { return base.GetHashCode(); 类型的,也就是调用了 object 的 GetHashCode 方法,其实和调用 RuntimeHelpers 的 GetHashCode 方法是相同的,因为在 object 方法里面的 GetHashCode
//返回xx该实例的哈希代码 xx.GetHashCode //返回xxx对象的实例id xxx.GetInstanceID 1️⃣ GetHashCode GetHashCode为获得该实例的哈希代码 、不同的Prefab,ID是不一样的 两个代码的区别 GetHashCode: 不仅可以获取物体、脚本等实例化出来物体的ID,还能获取声明变量的哈希值。
Hash 是散列的意思,就是把任意长度的输入,通过散列算法换成固定长度的输出,概述出就是散列值,关于散列值,有一下几个关键结论:
() == attribute2.GetHashCode() = {0}", attribute1.GetHashCode() == attribute2.GetHashCode()); 通过如下的输出结果我们可以看出这两个分明具有不同 () == attribute2.GetHashCode() = {0}", attribute1.GetHashCode() == attribute2.GetHashCode()); 5: Console.WriteLine ("attribute1.GetHashCode() == typeof(FooAttribute).GetHashCode() = {0}", 6: attribute1.GetHashCode ("attribute1.GetHashCode() == typeof(FooAttribute).GetHashCode() = {0}", 6: attribute1.GetHashCode 3: attribute1.GetHashCode() == typeof(FooAttribute).GetHashCode() = False 五、Attribute的GetHashCode
如果你试图通过 GetHashCode 得到的一个哈希值来避免冲突,你可能要失望了。 因为实际上 GetHashCode 得到的只是一个 Int32 的结果,而 Int32 只有 32 个 bit。 32 个 bit 的哈希,有多大概率是相同的呢?本文将计算其概率值。 对于 GetHashCode 得到的哈希值, 9292 个对象的哈希值冲突概率为 1%; 77163 个对象的哈希值冲突概率为 50%。 现在,我们推及到 GetHashCode 函数的重复情况。 GetHashCode 实际上返回的是一个 Int32 值,占 32 bit。也就是说,我们有 2^{32} 个数字可以选。 Hash Collision Probabilities 本文会经常更新,请阅读原文: https://blog.walterlv.com/post/hash-collisions-of-gethashcode.html
此 GetHashCode 方法推荐是在重写 Equals 方法时也同时进行重写,要求两个对象在 Equals 返回相等时,两个对象的 GetHashCode 返回值也相等。 这些哈希容器在设计上都期望类型遵守以下行为:当两个对象相等的时候,那么获取 GetHashCode 的值也一定相等 假定有类型的 GetHashCode 返回值是基于非只读的属性或字段,将会导致在将对象加入哈希容器的时候 ,所获取到的 GetHashCode 的值是不包括未来对非只读属性或字段变更的防御的。 在未来对此对象的非只读的属性或字段进行变更,也许就会影响到此对象再次获取 GetHashCode 的属性,从而让相同的一个对象,在哈希容器里面,因为 GetHashCode 返回值不同,而被认为是不同的对象 如果此时在 GetHashCode 里面,使用了非只读字段或属性,将会挖一个坑。
public static async void Excute() { Console.WriteLine(Thread.CurrentThread.GetHashCode() + " public static async void Excute() { Console.WriteLine(Thread.CurrentThread.GetHashCode public static async void Excute() { Console.WriteLine(Thread.CurrentThread.GetHashCode() + " 开始 Excute " + DateTime.Now); await SingleAwait(); Console.WriteLine(Thread.CurrentThread.GetHashCode() public static async void Excute() { Console.WriteLine(Thread.CurrentThread.GetHashCode() + " 开始
Equals与GetHashCode System.Object声明方法Equals和GetHashCode以及其他成员。 (注意:这个案例在C#中很重要)。您创建的类型会自动继承这些方法。 如果您覆盖Equals,则必须覆盖GetHashCode以保持一致性。 () { return base.GetHashCode() ^ mKey2.GetHashCode(); } } public () { return base.GetHashCode() ^ mKey3.GetHashCode(); } } public () { return base.GetHashCode() ^ mKey4.GetHashCode(); } } } 重载 public
C#中自定义类型会从Object类继承Equals和GetHashCode两个方法,可以根据实际需求来重写这两个方法实现对象相等性比较。 重写GetHashCode 重写Equals方法后,通常也需要重写GetHashCode方法,反之亦然。因为在哈希结构(如字典)中,存取数据时需要用到键的哈希码。 GetHashCode方法,尽可能在文档中指出:如果对象要用作哈希结构的key,尽可能不要修改该对象,否则,在读取数据时可能会引发KeyNotFoundException。 ⚠️ 不同的.NET版本、不同的平台(32位、64位系统)对于GetHashCode的默认实现可能会有差异。 The GetHashCode() method should not throw exceptions.
(), property); 6 7 return property; 8 } 用GetHashCode来标示我们这个属性的唯一性,这里我重写了这个函数它的值是this.ownerType.GetHashCode ()^this.propertyName.GetHashCode(),也就是说用注册这个属性的类型和属性的名称确定了这个扩展属性。 () ^ this.PropertyName.GetHashCode(); 4 if(defaultValue! () ^ name.GetHashCode(); 34 var property = ExtendPropertysProvider.Get(propertyKey); 35 (); 42 int key = this.GetHashCode() ^ propertyHash; 43 44 object result =
而重写object.GetHashCode(),则是一个最佳实践。 所有为值类型重定义相等性,一共分4步,每步都是必须的。 实现 先看实例struct: ? (如果你使用resharper或者Rider,那么实现该接口的时候它会自动把object的Equals和GetHashCode方法都重写了,并且自动完成了有意义的代码) ? 实现object.GetHashCode() GetHashCode()这个方法会返回一个32位的哈希码,它代表着对象内容的哈希值。 所以如果重写了object.Equals()方法,那么就得重写object.GetHashCode()方法。 看一下resharper自动实现的代码: ? 然后其它两个int和DateTime类型,微软都做好了其GetHashCode()的实现。 这里对它们进行异或操作。
规则说明 不应引发异常的方法可分成以下几类: 属性 Get 方法 事件访问器方法 Equals 方法 GetHashCode 方法 ToString 方法 静态构造函数 终结器 Dispose 方法 相等运算符 GetHashCode 方法 以下 GetHashCode 方法通常不应引发异常: GetHashCode GetHashCode GetHashCode 应始终返回值。 采用参数的 GetHashCode 版本可能会引发 ArgumentException。 但是,Object.GetHashCode 应始终不会引发异常。
Main(string[] args) { //当前线程标识 Console.WriteLine(Thread.CurrentThread.GetHashCode ()); Task task = new Task(run); Console.WriteLine("任务标识:" + task.GetHashCode ",状态:" + task.Status);//状态 task.Start(); Console.WriteLine("任务标识:" + task.GetHashCode () + ",状态:" + task.Status + ",当前线程:" + Thread.CurrentThread.GetHashCode());//状态 但是,经过我的测试发现,Task.GetHashCode()并不等于Thread.CurrentThread.GetHashCode()。
为此,System.Object提供了GetHashCode,它能获取任何对象的Int32哈希码.如果你定义的类型重写了Equals方法,还应重写GetHashCode方法。 如果你的类型重写了Equals方法,但是没有重写GetHashCode方法,C#编译器会发出一条警告,提示你重写GetHashCode方法,之所以重写Equals方法的同时要求重写GetHashCode 所以重写Equals就必须重写GetHashCode,确保相等性算法和对象哈希码算法一致. 自定义GetHashcode方法或许不是一件难事,但取决于数据类型和数据分布情况,可能并不容易设计出能返回良好分布值的哈希算法。 选择算法来计算类型实例的哈希码时,请遵守一下规则: 1、这个算法要提供良好的随机分布,使哈希表获得最佳的性能 2、可在算法中调用基类的GetHashCode方法,并包含它的返回值,但一般不要调用Object
代码运行的时候,CRL首先会调用Person类型的GetHashCode,由于发现Person没有实现GetHashCode,所以CLR最终会调用Object的 GetHashCode方法。 这是因为:Object为所有的CLR类型都提供了GetHashCode的默认实现。 想要修正该问题,就必须重写GetHashCode方法。 Person类的一个简单的重写可以是如下的代码: public override int GetHashCode() { return this.IDCode.GetHashCode ()); Console.WriteLine(str2.GetHashCode()); 这两个字符串产生的HasCode是一样的。
private readonly int _value; public S(int f) { _value = f; } public override int GetHashCode () => _value.GetHashCode(); public override bool Equals(object other) => other is private readonly int _value; public S(int f) { _value = f; } public override int GetHashCode () => _value.GetHashCode(); public override bool Equals(object other) => other is