C#中的类型相等与恒等(Equality & Identity)

CLR提供了可以区分类型的Equality 和Identity能力。

l  Equality:如果两个对象是相同的类型,并且它们各自带有相同和等值的属性。(They are instances of the same type and if each of the fields in one object matches the values of the fields in the other object)
Equality必须满足三个必要条件:reflexive, symmetrics, and transitive
reflexive: 自身相等,及a==a 是永远成立的;
symmetrics: 对象性,及a==b成立那么b==a 也成立;
transitive: 传递性,及a==b, b==c成立那么a==c 也成立。

l  Identity:两个对象必须相等(意味着他们共享同一块内存区域)(The two objects have the same values. – Two objects are identical if they share an address in memory)

CLR提供了至少四种方法来判断两个对象的等价性:

1.      Public static bool ReferenceEquals(object left, object right);

2.      Public static bool Equals(object left, object right);

3.      Public virtual bool Equals(object right);

4.      Public static bool operator==(MyClass left, MyClass right);

ReferenceEquals方法总是用来判断两个对象的Identity的,不管是针对值类型还是引用类型。所以针对值类型,调用该方法总是会返回false,因为值类型作为这个方法的参数时会进行装箱操作。

静态的Equals方法提供了判断两个对象的Equality能力,在其实现的内部,调用了上述第三个虚拟的Equals方法。和ReferenceEquals一样,它们已经具备从底层判断两个对象的能力,我们从来不会覆写这两个方法。

实例Equals方法也是用来区分两个对象的Equality的。

l  对于引用类型的对象,它和ReferenceEquals方法几乎是一样的。(因为判断两个引用类型是否的Equality往往从Identity上就可以区分)

l  而值类型的对象,我们不仅要判断他们具有相同的对象类型,还要判断他们的值相等。值类型从System.ValueType继承而来,ValueType已经重写了Object.Equals()方法,本来已经可以用来满足这些要求的。但是ValueType.Equals()方法不是很有效,因为它必须要通过反射,在不知道具体的派生类型中,完成对它们所含有成员变量的值的比较。因此,建议在我们实现一个值类型的数据结构时,同时重写ValueType.Equals()方法。

l  然而我们再回头看看引用类型,有时两个引用类型的对象往往被用来进行类似值类型的比较,比如:String类型,它虽然是引用类型,但它也重写了Equals方法,因为我们拿它来判断两个string是否相同(Equality),实际是希望判断它们是否具有相同的内容,这是一个value semantics。因此,我们建议在考虑实现一个用作值语义环境下的引用类型时候,也重写基类的Object.Equals()方法。

注:请参考MDSN或其它相关文档,如何实现Equals方法的重写。

上面的图示给了很好的例子来区分Equals和ReferenceEquals方法,被用来做Equility和Identity判断的区别。

==运算符是可由类重载的运算符,它也是用来判断恒等的。
对于未重载==的引用类型,会比较两个引用类型是否引用同一个对象。这跟引用类型的Equals()方法是一样的。

对于未重载==的值类型,该运算符会比较这两个值是否"按位"相等,即是否这两个值中的每个字段都相等。和Equals方法一样,推荐在自定义值类型中,也要重载==运算符,因为也存在反射在效率上的影响。

==运算符和Equals方法的区别在于多态表现上。Equals方法是重写,而==运算符是被重载。这意味着除非编译器知道调用具体的重载版本,否则它只是调用未重载的==版本。

参考资料:
《Essential .NET, Volume 1: The Common Language》 By DonBox, Chris Sells
《Applied Microsoft .NET Framework Programming》By Jeffrey Richter

时间: 2024-11-08 18:23:50

C#中的类型相等与恒等(Equality & Identity)的相关文章

C#中的类型相等与恒等(Equality & Identity)

CLR提供了可以区分类型的Equality 和Identity能力. l Equality:如果两个对象是相同的类型,并且它们各自带有相同和等值的属性.(They are instances of the same type and if each of the fields in one object matches the values of the fields in the other object) Equality必须满足三个必要条件:reflexive, symmetrics, a

JScript中值类型的封箱与拆箱

js|jscript JScript中对象的expando属性是对Object,Array等引用类型增加成员的一种重要手段,但这种手段在对值类型时就不行了,比如var str = "string1";str.method1 = function(){//do something}; str.method1();//这里将出错,错误信息(我忘记了)是说str不存在该方法 这样的语句就会运行不了,而在C#编程中值类型存在装箱与拆箱操作来将其转换为引用类型,对此,JScript中也存在值类型

PHP中的类型提示(type hinting)功能介绍

  这篇文章主要介绍了PHP中的类型提示(type hinting)功能介绍,本文讲解了类型提示的作用和使用方法以及使用示例,需要的朋友可以参考下 概述 从PHP5开始,我们可以使用类型提示来指定定义函数时,函数接收的参数类型.如果在定义函数时,指定了参数的类型,那么当我们调用函数时,如果实参的类型与指定的类型不符,那么PHP会产生一个致命级别的错误(Catchable fatal error). 类名称和数组 在定义函数时,PHP只支持两种类型声明:类名称和数组.类名称表名该参数接收的实参为对

PHP中的类型约束介绍

  这篇文章主要介绍了PHP中的类型约束介绍,PHP的类方法和函数中可实现类型约束,但参数只能指定类.数组.接口.callable 四种类型,参数可默认为NULL,PHP并不能约束标量类型或其它类型,需要的朋友可以参考下 PHP的类方法和函数中可实现类型约束,但参数只能指定类.数组.接口.callable 四种类型,参数可默认为NULL,PHP并不能约束标量类型或其它类型. 如下示例: 代码如下: class Test { public function test_array(array $ar

ztree中json类型数据如何在前台显示?

问题描述 ztree中json类型数据如何在前台显示? 后台从数据库中获取到相应数据,存储到list,然后将list转换为json类型,返回到前台,通过ajax接收 前台代码如上所示,不显示树形结构,请问是哪里出现了问题. 解决方案 debug一下看看json数据 ,网上有成型的 照猫画虎 解决方案二: 已解决此问题: 请注意看上图treeNodesdata,success中传过来的是treeNodes,而我在树初始化的时候传过来的变量写的是treeNodes.直接将后台的json传到前台,前台

方法-python中的类型怎么对应java中的byte[]

问题描述 python中的类型怎么对应java中的byte[] 场景是这个样子的我这边要实现一个接口 服务器端是java做的客户端是python做的服务器端向客户端提供了一个login的接口需要客户端实现login需要给服务器返回一个byte[] 的值 但是python中貌似没有byte这个类型我该怎么处理?bytearray 这个方法试过了 貌似不行 在线等好心人 求大神给我点一下啊 卡到这里很长时间了很紧 啊 解决方案 https://gist.github.com/igniteflow/1

ios-在iPhone4S和iPhone5设备中文本类型

问题描述 在iPhone4S和iPhone5设备中文本类型 在iPhone4中下面的代码会输出iPhone,在iPhone4s和iPhone5中会输出什么?我没有真机,但是需要调试iPhone所有版本的调用功能. 谢谢~ 解决方案 输出还是iPhone

mfc-MFC中字符串类型的浮点数,如何辨别是float还是dpuble

问题描述 MFC中字符串类型的浮点数,如何辨别是float还是dpuble CFILE读取字符串类型的浮点数,如何辨别是float还是double,如果是float转换为float,否则转换为double 解决方案 转换成字符串没法判断,只有一种情况,就是数据超过float表示的范围,那么可以判定是double,在两者共同的精度范围没法判断. 解决方案二: 字符串的话应该没法弄吧,这个你直接接受时候就是数字可以搞 解决方案三: 没有必要判断啊,直接都用double,然后在格式化字符串的时候空格下

请教一个link引用化的问题?link中哪些类型需要引用化,除了数组泛型还有么?

问题描述 请教一个link引用化的问题?link中哪些类型需要引用化,除了数组泛型还有么? 请教一个link引用化的问题?link中哪些类型需要引用化,除了数组泛型还有么? 解决方案 C#分为引用类型和值类型,int cha还有结构体是值类型,别的事引用类型.