【转载】聊一聊C#的Equals()和GetHashCode()方法

【转载】聊一聊C#的Equals()和GetHashCode()方法

首先先谈一下Equals()这个方法:

Equals()方法,来自于Object,是我们经常需要重写的方法。此方法的默认实现大概是这样的:

public virtual bool Equals(object obj)

{

  if(obj==null) return false;

  if(GetType() != obj.GetType()) return false;

  Return true;

}

由此可以看出,默认的实现其实比较的是两个对象的内存地址(==操作符默认比较内存地址)。值类型和string类型除外,因为所有值类型继承于System.ValueType()(System.ValueType()同样继承于Object,但是System.ValueType()本身却是引用类型),而System.ValueType()对Equals()和==操作符进行了重写,是逐字节比较的。而string类型是比较特殊的引用类型,所以strIng在很多地方都是特殊处理的,此处就不做深究了。

Ps:按Jeffrey Richter的说法,在值类型使用Equals()时,因为Equals()使用了反射,在比较时会影响效率。

说完Equals()后再来聊一聊GetHashCode()。

其实GetHashCode()在操作值类型的时候也是被System.ValueType()重写的。经过楼主测试的几个常用值类型来看,值类型的GetHashCode()基本都是原值输出(特指整数,Int32除外),真实性有待验证。结果如下:

<span>【转载】聊一聊C#的Equals()和GetHashCode()方法</span>

说完值类型,说一下引用类型,先看下面这张运行结果:

<span>【转载】聊一聊C#的Equals()和GetHashCode()方法</span>

从上图的结果可以看出,虽然string是引用类型,但是只要值一样,返回的HashCode也是一样的,这取决于它的特殊性。而我们自己写的类型Coordinates同样的值但返回的HashCode却不一样,我们可以简单的理解为是coor1与coor2的内存地址不同,所以CLR认为它们是不一样的。

Ps:在程序的生命周期中,相同的对象、变量返回的HashCode是相同的,并且是唯一的。但是绝对不允许做持久性存储,程序一旦结束并重新启动后,同样的对象无法获得上次程序运行时的HashCode。

了解了两个方法后,开始今天的重点话题。

其实在上面的两个对象中(coor1、coor2),coor1.Equals(coor2)的返回结果为false(因为内存地址不同),如果我们想让它们的返回结果为true的话,只能重写Equals方法(如下图)。

<span>【转载】聊一聊C#的Equals()和GetHashCode()方法</span>

重点来了,重写完Equals以后,vs发出了警告,虽然程序猿从来都是无视警告的,但这个警告确实有必要了解一下,先来看下面这三段代码。

代码段一、二:

<span>【转载】聊一聊C#的Equals()和GetHashCode()方法</span>

代码段三:

<span>【转载】聊一聊C#的Equals()和GetHashCode()方法</span>

看完这三段代码,应该就理解为什么要重写Equal时有必要重写GetHashCode了。

当然,如果你没打算在代码中使用Dictionary或HashTable就无所谓写不写了,换句话说,如果要把引用类型做为Dictionary或HashTable的key使用时,必须重写这两个方法。

原因:当我们把引用类型(string除外)做为Dictionary或HashTable的key时,有可能永远无法根据Key获得value的值,或者说两个类型的HashCode永远不会相等。就拿Dictionary来说,虽然我们存储的时候是键值对,但是CLR会先把key转成HashCode并且验证Equals后再做存储,根据key取值的时候也是把key转换成HashCode并且验证Equals后再取值,一定要注意验证时HashCode和Equals的关系是并且(&&)的关系。也就是说,只要GetHashCode和Equlas中有一个方法没有重写,在验证时没有重写的那个方法会调用基类的默认实现,而这两个方法的默认实现都是根据内存地址判断的,也就是说,其实一个方法的返回值永远会是false。其结果就是,存储的时候你可能任性的存,在取值的时候就是你哭着找不着娘了。

好了,说了这么多你应该对这两个方法有了重新的认识了吧。如果还是不明白的话,用代码实现一下,保准明白。

 

【转自】https://www.cnblogs.com/xiaochen-vip8/p/5506478.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/119336.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 超详细的数据分析职业规划

    超详细的数据分析职业规划最近有不少同学向大讲台老师咨询有关数据分析职业发展的问题,由此可见,随着大数据的飞速发展,数据分析职业也成为很多同学关注的目标。不要急,大讲台老师这就给大家介绍数据分析的职业发展。入门和职业规划应该从两个角度考虑:领域和路线。领域是不少新人常忽略的要素,其实数据分析不会脱离业务存在。你进入哪个行业,很大程度会决定你初期的技能树和技能点。譬如金融领域的风控模型、营销领域的生命周期、广告

  • jediscluster.set加锁_redislock

    jediscluster.set加锁_redislock一、前置配置需要已经集成成功JedisCluster本人已实践的参考:https://blog.csdn.net/NullToSay/article/details/109813194二、定义RedisLock类importorg.apache.commons.lang.StringUtils;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importredis.clients.jedis.JedisClust.

    2022年10月14日
  • python之Beautiful Soup库

    1、简介简单来说,BeautifulSoup是python的一个库,最主要的功能是从网页抓取数据。官方解释如下:BeautifulSoup提供一些简单的、python式的函数用来处理导航、搜索

    2021年12月29日
  • 图集谷-写真集-爬虫-1.0[通俗易懂]

    图集谷-写真集-爬虫-1.0[通俗易懂]图集谷写真集爬虫

  • 经典中的经典算法:动态规划(详细解释,从入门到实践,逐步讲解)

    经典中的经典算法:动态规划(详细解释,从入门到实践,逐步讲解)首先,本博客为原创作品,欢迎指导,随意转载,如果可以请转载时说明出处,附上本文链接,谢谢动态规划的重要性就不多说,直接进入正题首先,我们看一下官方定义:定义:动态规划算法是通过拆分问题,定义问题状态和状态之间的关系,使得问题能够以递推(或者说分治)的方式去解决。动态规划算法的基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题…

  • FPGA中实现对数运算「建议收藏」

    FPGA中实现对数运算「建议收藏」FPGA中实现对数运算主要有三种方法:(1)在外部直接算好对数值,按照数值范围做个表,存在ram里,到时候查表。为了减少表深度,提高资源利用率,可以考虑去掉部分低位数值,损失一定的精度。(2)使用cordic算法求解对数。(3)log10(x)=ln(x)*log10(e),log10(e)是常数可以手动先计算好,用IPCore的话多个乘法器。下面介绍使用IP核fl…

    2022年10月29日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号