为什么(对象)0 ==(对象)0不同于((对象)0).Equals((对象)0)?
为什么下面的expression方式不同?
[1] (object)0 == (object)0 //false [2] ((object)0).Equals((object)0) // true
实际上,我完全可以理解[1],因为.NET运行时可能会box
整数并开始比较引用。 但为什么[2]不同?
调用行为不同的原因是它们绑定到非常不同的方法。
==
情况下将绑定到静态引用相等运算符。 有2个独立的盒装int
值创build,因此他们不是相同的参考。
在第二种情况下,您绑定到实例方法Object.Equals
。 这是一个虚拟的方法,将过滤到Int32.Equals
,这将检查盒装整数。 两个整数值都是0,因此它们是相等的
当您将int值0
(或任何其他值types)转换为object
,该值将被装箱 。 每个投射到object
产生一个不同的盒子(即不同的对象实例)。 object
types的==
运算符执行引用比较,所以它返回false,因为左侧和右侧不是同一个实例。
另一方面,当使用Equals
(虚拟方法)时,它使用实际的盒装types的实现,即Int32.Equals
,由于两个对象具有相同的值,所以它返回true。
==
运算符是静态的,不是虚拟的。 它将运行object
类定义的确切代码(对象是操作数的编译时types),不pipe任何对象的运行时types如何,它都将执行引用比较。
Equals
方法是一种虚拟实例方法。 它将运行在(第一个)对象的实际运行时types中定义的代码,而不是object
类中的代码。 在这种情况下,该对象是一个int
,所以它将执行值的比较,因为这是int
types为其Equals
方法定义的。
Equals()
方法是虚拟的。
因此,即使在调用object
时候,它总是调用具体的实现。 int
重写Equals()
以按值进行比较,因此您可以获得值的比较。
==
使用: Object.ReferenceEquals
Object.Equals
比较值。
object.ReferenceEquals
方法比较引用。 分配对象时,除了内存堆中的对象数据之外,还会接收到一个引用,其中包含一个指示其内存位置的值。
object.Equals
方法比较对象的内容。 它首先检查引用是否相等,像object.ReferenceEquals一样。 但是接着调用派生的Equals方法来进一步testing等式。 看到这个:
System.Object a = new System.Object(); System.Object b = a; System.Object.ReferenceEquals(a, b); //returns true
C#运算符使用标记==
来表示两个不同的运算符:静态可重载比较运算符和不可重载参考比较运算符。 当它遇到==
标记时,它首先检查是否存在适用于操作数types的任何相等testing过载。 如果是这样,它会调用这个过载。 否则,将检查这些types是否适用于参考比较运算符。 如果是这样,它将使用该操作员。 如果两个操作符都不适用于操作数types,则编译将失败。
代码(Object)0
不仅仅是将Int32
上传到Object
: Int32
与所有值types一样,实际上代表两种types,其中一种描述值和存储位置(例如文字零),但不是从任何东西,其中一个描述堆对象并从Object
派生; 因为只有后者types可能被上传到Object
,编译器必须创build一个新的后一types的堆对象。 (Object)0
每次调用都会创build一个新的堆对象,所以两个==
操作数是不同的对象,每个对象独立地封装Int32
值0。
类Object
没有为等号运算符定义任何可用的重载。 因此,编译器将无法使用重载的等式testing运算符,并将回退到使用引用相等testing。 因为==
的两个操作数引用了不同的对象,所以它会报错。 第二个比较成功,因为它要求Int32
一个堆对象实例是否等于另一个。 因为该实例知道与另一个不同的实例相等意味着什么,所以它可以回答true
。
两个检查都不一样。 第一个检查身份 ,第二个检查是否平等 。 一般而言,两个术语是相同的,如果它们是指同一个对象的话。 这意味着它们是平等的。 两个术语是相同的,如果他们的价值是相同的。
在编程方面,身份通常是由参考平等所左右。 如果这两个词的指针是相同的(!),它们指向的对象是完全一样的。 但是,如果指针不同,它们所指向的对象的值可能仍然相等。 在C#中,可以使用静态Object.ReferenceEquals
成员来检查标识,而使用非静态Object.Equals
成员检查相等性。 既然你将两个整数转换为对象(称为“装箱”,btw), object
的操作Object.ReferenceEquals
==
执行第一次检查,默认情况下,它将映射到Object.ReferenceEquals
并检查身份。 如果你明确地调用非静态Equals
成员, dynamic调度将导致对Int32.Equals
的调用,这会检查是否相等。
这两个概念是相似的,但不一样。 他们可能看起来很迷惑,但小的差异是非常重要的! 设想两个人,即“爱丽丝”和“鲍勃”。 他们都住在一个黄色的房子里。 基于这样的假设,爱丽丝和鲍勃住在一个只有房屋颜色不同的地区,他们都可以住在不同的黄房子里。 如果你比较两个家庭,你会认识到,他们是绝对相同的,因为他们都是黄色的! 然而,他们并没有分享同一个家,所以他们的房子是平等的 ,但不完全相同 。 身份意味着他们住在同一个房子里。
注意 :有些语言正在定义===
运算符来检查身份。