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

聊一聊C#的Equals()和GetHashCode()方法

 

博客创建一年多,还是第一次写博文,有什么不对的地方还请多多指教。

关于这次写的内容可以说是老生长谈,百度一搜一大堆。大神可自行绕路。

最近在看Jeffrey RichterCLR Via C#,在看到GetHashCode()方法的时候,有一个地方不是特别明白,就是重写Equals()方法时为什么要把GetHashCode()方法一块重写(不重写也没关系,但是微软会发送一条警告)。在解释这个问题之前需要先把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除外),真实性有待验证。结果如下:

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

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

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

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

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

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

代码段一、二:

 

代码段三:

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

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

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

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

 

原贴:http://www.cnblogs.com/xiaochen-vip8/articles/5506478.html 

来源:http://www.cnblogs.com/refuge/p/8597668.html


智能推荐

在聊Java中的equals方法

作者简介: 华哥 10年+后端开发工作经验, 主要分享:关于java体系的知识,如:java基础知识/数据结算/算法,Spring/MyBatis/Netty源码分析,高并发/高性能/分布式/微服务架构的原理,JVM性能优化等。 公众号:java杂记   java规范中equals方法特征 自反性(对于任何非空引用x, x.equals(x) 返回true;) 对称性(对于任何引用x, ...

聊一聊 :C语言的特性

  在过去40年里,C语言已成为最重要、最流行的流程语言之一。它的成功有很多的点,但都跟其四大优秀的特性分不开:高效性、可移植性、强大而高效和面向程序员。下面我们来具体聊聊它的特性把 ​​​​​​​​​​​​​​​​​​​​​高效性:C是高效的语言,在设计上,充分利用了计算机的优势,因此C语言程序相对比较紧凑,运行速度很快,通常C语言具有汇编语言才有的微调控制能力,可以根据具体情况微调程...

C#数组中CopyTo()和Clone()的区别(转)

有很多初学者会对CopyTo()和Clone()的区别弄不清楚.在网上搜索一下,大多数解说的程序员都把问题引到浅拷贝和深拷贝的区别上去了,关于浅拷贝和深拷贝确实解释的很清楚,可是这并没有让初学者减轻疑惑.所以特此写点东西,解释下这两个方法的共同点和区别,同时解释下浅拷贝和深拷贝. 相信大多数C#程序员都有查阅MSDN的好习惯,但是MSDN中提到这两个方法最大的区别就是:一个方法创建了一个新Arra...

Java和C#的socket通信相关(转)

这几天在博客园上看到好几个写Java和C#的socket通信的帖子。但是都为指出其中关键点。 C# socket通信组件有很多,在vs 使用nuget搜索socket组件有很多类似的。本人使用的是自己开发的一套组件。 Java socket通信的组件也有很多,常用的大多数都是用的mina或者netty。游戏行业使用也是居多。 关于socket的底层写法,实在太多,我就不在BB。 这里我想说,C#和...

【转】C#调用WebService

转自:http://www.cnblogs.com/denylau/archive/2010/07/23/1783530.html   1.1、Web Service基本概念 Web Service也叫XML Web Service WebService是一种可以接收从Internet或者Intranet上的其它系统中传递过来的请求,轻量级的独立的通讯技术。是:通过SOAP在Web上提供...

猜你喜欢

C#异步编程(转)

C#异步编程   在使用多线程编写端口扫描程序时,我自己感觉同步和确定所有线程都执行完的时间是2个比较麻烦的问题。有园友评论说现在已经不手动创建thread对象了,而是直接使用Task异步方式,我的网络编程老师也讲到了异步编程的优越性。在学习了课本上的知识后,进行了一个总结分享给大家。从.NET4.5开始,用async和await关键字再加上Task.Run是一个非常不错的异步编程模型。 1.aw...

c#串口编程(转)

在单片机项目开发中,上位机也是一个很重要的部分,主要用于数据显示(波形、温度等)、用户控制(LED,继电器等),下位机(单片机)与 上位机之间要进行数据通信的两种方式都是基于串口的: USB转串口 —— 上位机和下位机通过USB转串口连接线直接相连进行数据交互; 串口转WIFI(ESP8266) ——  上位机和下位机基于TCP/IP协议通...

The Design of Everyday Things 读书笔记

  近日抽闲读了老师推荐已久的这部设计史上的著作——唐纳德诺曼的The Design of Everyday Things,中文译名是《设计心理学》,全套共四部,我读了第一部,总的感觉就一个词——恍然大悟!被作者的细心以及擅于思考所折服,他能够抓住生活中很多人习以为常的不方便和小错误,从而解释糟糕的设计可能带给我们的麻烦甚至灾难。...

博客,记录一点一滴,终将汇聚成星辰大海

博客,记录一点一滴,终将汇聚成星辰大海 目录 写博客的好处: 要怎么写博客: 写博客的好处: 【1】我认为写博客能充当自己的资料库,你能随时翻阅你之前学的所有东西,你是否有这样的经历,明明自己之前学过这方面的内容,而且还挺熟悉,但怎么都记不起来具体细节,这时候你的资料库就能最快帮你回忆起你学的东西。 【2】把自己学到的经验,分享出来,自己之前踩到的所有坑都记录下来,当读者读你的博客时,就能少走一些...

一个好玩的工具BeEF介绍及未来要实验

beef BeEF-XSS是一款非常强大的web框架攻击平台,集成了许多payload,可以实现许多功能 BeEF-XSS可以说是最强大的XSS漏洞利用工具,可以收集浏览器信息、键盘记录、社会工程等 总之就是使用beef这个工具来利用xss漏洞的 beef安装 我在kail虚拟机上安装的,很简单的在终端输入一句命令sudo apt setup beef-xss,然后安装成功设置密码就行了,因为之后...

问答精选

Applying stats.percentileofscore to every row by column

df= I need a new column with the percentile score for each element with respect to the column. The final answer should look like this. I want the output of the stats.percentileofscore() function to be...

C - Creating node with multiple children by function - segmentation fault

I want to create tree with multiple children and create every node with a function. Here is my structure for node: And here is my function to create new node (with four children): When I run this func...

How to get all secrets in one call Azure key vault

I am using sample code explain here https://github.com/Azure-Samples/app-service-msi-keyvault-dotnet but they only explained how can we get single secrete not list of secrete. so to get all secrete I'...

increase eclipse IDE font size

I am using Eclipse I would like to increase the font size of the IDE, not just the font of the editor. Is there any way I can do that? I haven't been able to find a solution for this yet. you can try ...

Generating Guid by database automatically

It regards Entity Framework 6 but maybe it isn’t related to the version. I have some class which has Guid Id but by inheritance. Right now I would like to change this model to auto generate Id b...

相关问题

相关文章

热门文章

推荐文章

相关标签

推荐问答