An article about Equals and GetHashCode functions in C#
来源:互联网 发布:网络无线机顶盒接收器 编辑:程序博客网 时间:2024/05/23 02:02
引言
Object类是C#中所有类型的基类,但由于对它的继承是隐式的,故大多数人对它并不太在意,其实object中包含了很多有用的方法,对它有个清晰的了解能够很好地帮你理清楚c# API的层次结构,本文就Object中6个方法进行简单的说明,重点讲述Equals方法。
综述
在.Net中,每一个类型都继承自一个公共的基类:System.Object。Object类定义了.NET世界中每一个类型都支持的一组公共的成员集合。当创建任何一个不显示指定其基类的类时,它隐含继承自System.Object,当然,你也可以显示地继承。下面来看一下,System.Object的接口:
可以看出,Object类主要包含四个虚方法,子类可以重写它,应该说这几个是比较常用的(除了Finalize());两个静态方法,object对其有具体实现,可以直接使用;两个实例方法,GetType在反射中用的比较多,MemberwiseClone在实现ICloneable接口时比较常用。至此,相信大家对object应该有了一个整体的认识,下面分别对它的几个方法成员进行描述。
应用
1 ToString() : 自描述
用一句话来概括ToString()方法的作用,我觉得应该是“提供了一种获得对象当前状态的快照”。object类对它的默认实现是返回该对象的完全限定名,也就是说,如果你定义的类没有重写ToString()方法,那么直接调用当前对象的ToString()方法,返回的是一个字符串:命名空间+类名。如下面的代码,输出的结果是: ConsoleApplication.Program
上面已经说了,ToString()方法主要用来返回对象当前状态的一个快照,故如果我们在项目中有这种需求,就应该重写该方法。下面写个简单的代码实例,后面几个方法的说明都会围绕这个实例说明。如果做网络协议方面的开发,经常会遇到各种各样的Error Code,下面我们设计一个简单的类,用来描述一个网络操作的返回结果,代码如下:
Status类包括两个数据成员,errorCode 和 errorString,分别用来描述错误码和错误提示信息,这里是为了简单化,实际的开发中errorCode一般是设计成enum类型的,易于标识。接着,我们在Status类中重写ToString()方法,代码如下:
代码很简单,就是将当前对象的数据以一定的形式输出来,下面我们写个客户端代码简单测试下:
小结:ToString()方法主要用来描述对象的当前状态,在某些特定应用中非常有用,比如在一些网络协议中,我们需要以Http Get的方式发送数据给服务器,那么构建url就是个必须的工作,如果只是简单几个参数可能比较容易构建,但是一旦需要传递的参数很多,那么比较OO的做法就是构建一个类,将那些需要传递的数据作为数据成员封装好,然后重写ToString()方法,将对象的数据按照url要求的格式组织好返回。
2 Equals(): 判等
Equals相关的方法总共有三个,Equals(Object, Object) : Boolean; ReferenceEquals(Object, Object) : Boolean; Equals(Object) : Boolean。前两个方法object已经提供了具体的实现,对于ReferenceEquals,顾名思义,是用来判断两个对象的引用是否相同,需要注意两点:
1 如果传入两个null对象,返回true。
2 由于ReferenceEquals的两个参数都是Object类型的,如果传入值类型将会进行装箱,由此会导致引用不相同,比如代码:Object.ReferenceEquals(2, 2),返回的是false,因为对2进行装箱以后倒置两者指向了不同的引用。如果这样写呢:int n = 2; Object.ReferenceEquals(n, n); 返回的依然是false。
接着,简单说明一下Equals(Object, Object) : Boolean,.NET中对它的实现如下:
流程如下:
判断两个对象是否指向同一个引用(包括两者为null的情况),如果是则返回true,否则继续进行;
如果两者都不为null的时候,返回的结果取决于实例方法Equals的返回值。
object对Equals(Object)的默认实现是只有当两个对象指向相同的引用才返回true,下面我们来对该方法进行重载,代码依旧在Status的基础上改,加一个方法,代码如下:
先判断obj对象是否为null以及它的类型,如果它是一个非空的Status类型则比较对象的值,相等则返回true。修改Main方法,对Equals方法进行测试:
输出结果为True,倘若没有重写Equals方法,输出的将是False,因为两者的状态数据相同,但是指向不同的引用。
重写了Equals方法后,重载 == 和 != 运算符其实也是件很容易的时,直接调Equals方法即可,但是引用《Effective c#》中的建议:
1 定义==重载函数的时候,也要定义!=重载函数。
2 值类型最好不要重载定义Equals函数,而引用类型最好不要重载定义==操作符。
至此,有关Equals就介绍到这,相信大家对它应该有了一个清晰的认识,接着我们来看Object下一个与Equals密切相关的成员方法。
3 GetHashCode(): 对象地址
GetHashCode()方法返回一个能够标识内存中指定对象的整数,如果你打算将自定义的类型包含进System.Collections.HashTable类型中,强烈建议你重写这个方法的默认实现。当我们重写了Equals(Object)实例方法后,编译器会产生一个警告,建议你同时也重写GetHashCode方法。GetHashCode的作用是返回一个数值,又叫散列码,它根据对象的内部状态数据表识对象。因此,如果两个对象的状态数据相同,也应该获得相同的散列码。一般来说,重写GetHashCode只在打算将自定义的类型保存在一个基于散列值的集合中时有用。在底层,HashTable类型调用所含类型的GetHashCode()以及Equals()成员来确定要返回给调用者的正确对象。
创建散列码的算法有很多,这里不做说明,System.String类提供了一个可靠的GetHashCode()的实现,它基于字符串的字符数据。如果能确定某个字符串字段在对象之间是唯一的,例如id,那么就可以直接对这个字段的字符串调用GetHashCode();如果找不到这样一个唯一型字段,但已经重写了ToString(),可以直接从它GetHashCode(),对于Status类,由于我们已经实现了ToString()方法,就可以这样简单实现GetHashCode方法,代码如下:
有关HashCode是否有效的判断标准,引用《Effective C#》中描述如下:
1. 如果两个对象相等(由operator==定义),它们必须产生相同的散列码。否则,这样的散列码不能用来查找容器中的对象[22]。
2. 对于任何一个对象A,A.GetHashCode()必须是一个实例不变式(invariant)。即不管在A上调用什么方法,A.GetHashCode()都必须总是返回相同的值。这可以确保放在“散列桶”中的对象总是位于正确的“散列桶”中。
3. 对于所有的输入,散列函数应该在所有整数中产生一个随机的分布。这样,我们才能从一个散列容器上获得效率的提升。
那么如果两个对象不相等能否产生相同的散列码呢? 网上搜了一下,看到有网友发的一段代码,似乎对于不同的状态数据,是可以返回相同的散列码,不信运行下面代码试一下:
返回的结果都是:2060653827
想要了解更多有关GetHashCode()方法的描述,可以参考《Effective C#: 改善C#程序的50种方法》
- An article about Equals and GetHashCode functions in C#
- An article about Equals and GetHashCode functions in C#
- An usage about "equals ()"
- An old article about OpenBSD project & Theo
- An article about the java serialization algorithm
- MD5, SHA1, SHA256 and SHA512 Hash Algorithm Functions in C#
- GetHashCode与Equals双刃剑
- Some functions and codes about date
- C# GetHashCode in the IEqualityComparer<T> in .NET
- An Introduction to Dynamic Management Views and Functions in SQL Server 2005
- An understanding of two important built-in functions(__str__ And __repr__)
- There is an obvious Error in npp src. ( About FORTRAN Syntax Highlighting And Fold )
- An article about hash function for hash table
- C# Dictionary中做Key的类应该注意重写getHashCode和Equals
- C#学习笔记第四篇之Equals,GetHashCode ,ToString函数深度剖析(一)
- C#学习笔记第四篇之Equals,GetHashCode ,ToString函数深度剖析(二)
- C# Dictionary中做Key的类应该注意重写getHashCode和Equals
- An interesting document about c10k and more
- 用户是否登录验证--过滤器
- 10个CSS简写技巧让你永远受用
- 线性表的链式表示与实现
- 一个简单程序的分析----深至内核
- 直播星升级:造福渠道,用户遭殃
- An article about Equals and GetHashCode functions in C#
- 《世界因你不同》——去微软,回中国
- 网络爬虫-Heritrix 和 Nutch比较与分析
- 注册表的文件类型关联[转]
- XML 显示双引号
- 人民币利率水平(2010.10.20之前)
- C#在进度条中显示复制文件的进度
- c# 支持XML序列化的泛型 Dictionary
- 简单HTML 字体,颜色表示(转载)