为什么(对象)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产生一个不同的盒子(即不同的对象实例)。 objecttypes的==运算符执行引用比较,所以它返回false,因为左侧和右侧不是同一个实例。

另一方面,当使用Equals (虚拟方法)时,它使用实际的盒装types的实现,即Int32.Equals ,由于两个对象具有相同的值,所以它返回true。

==运算符是静态的,不是虚拟的。 它将运行object类定义的确切代码(对象是操作数的编译时types),不pipe任何对象的运行时types如何,它都将执行引用比较。

Equals方法是一种虚拟实例方法。 它将运行在(第一个)对象的实际运行时types中定义的代码,而不是object类中的代码。 在这种情况下,该对象是一个int ,所以它将执行值的比较,因为这是inttypes为其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上传到ObjectInt32与所有值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的调用,这会检查是否相等。

这两个概念是相似的,但不一样。 他们可能看起来很迷惑,但小的差异是非常重要的! 设想两个人,即“爱丽丝”和“鲍勃”。 他们都住在一个黄色的房子里。 基于这样的假设,爱丽丝和鲍勃住在一个只有房屋颜色不同的地区,他们都可以住在不同的黄房子里。 如果你比较两个家庭,你会认识到,他们是绝对相同的,因为他们都是黄色的! 然而,他们并没有分享同一个家,所以他们的房子是平等的 ,但不完全相同 。 身份意味着他们住在同一个房子里。

注意 :有些语言正在定义===运算符来检查身份。