为什么以下表达式不同?
[1] (object)0 == (object)0 //false
[2] ((object)0).Equals((object)0) // true
实际上,我完全理解[1]因为.NET运行时可能会box
整数并开始比较引用。但为什么[2]会有所不同?
答案 0 :(得分:151)
调用行为不同的原因是它们绑定到非常不同的方法。
==
大小写将绑定到静态引用相等运算符。创建了2个独立的盒装int
值,因此它们不是相同的参考。
在第二种情况下,您绑定到实例方法Object.Equals
。这是一个虚拟方法,它将过滤到Int32.Equals
并检查一个盒装整数。两个整数值都是0因此它们相等
答案 1 :(得分:26)
将int值0
(或任何其他值类型)强制转换为object
时,值为框。每次转换为object
都会生成一个不同的框(即不同的对象实例)。 ==
类型的object
运算符执行引用比较,因此它返回false,因为左侧和右侧不是同一个实例。
另一方面,当你使用Equals
这是一个虚方法时,它使用实际的盒装类型的实现,即Int32.Equals
,它返回true,因为两个对象具有相同的值
答案 2 :(得分:18)
==
运算符是静态的,不是虚拟的。它将运行object
类定义的确切代码(`对象是操作数的编译时类型),它将执行引用比较,而不管任一对象的运行时类型。
Equals
方法是一种虚拟实例方法。它将运行在(第一个)对象的实际运行时类型中定义的代码,而不是object
类中的代码。在这种情况下,对象是int
,因此它将执行值比较,因为这是int
类型为其Equals
方法定义的内容。
答案 3 :(得分:13)
Equals()
方法是虚拟的
因此,即使将调用点转换为object
,它也始终调用具体实现。
int
会覆盖Equals()
以按值进行比较,因此您可以进行值比较。
答案 4 :(得分:10)
==
使用:Object.ReferenceEquals
Object.Equals
比较值。
object.ReferenceEquals
方法比较引用。分配对象时,除了对象在内存堆上的数据外,还会收到一个包含指示其内存位置的值的引用。
object.Equals
方法比较对象的内容。它首先检查引用是否相等,object.ReferenceEquals也是如此。但随后它调用派生的Equals方法来进一步测试相等性。
见:
System.Object a = new System.Object();
System.Object b = a;
System.Object.ReferenceEquals(a, b); //returns true
答案 5 :(得分:9)
C#运算符使用标记==
来表示两个不同的运算符:静态可重载的比较运算符和不可重载的引用比较运算符。遇到==
令牌时,它首先检查是否存在适用于操作数类型的任何相等测试重载。如果是这样,它将调用该重载。否则,它将检查类型是否适用于引用比较运算符。如果是这样,它将使用该运算符。如果两个运算符都不适用于操作数类型,则编译将失败。
代码(Object)0
不只是将Int32
转发为Object
:Int32
,与所有值类型一样,实际上代表两种类型,其中一种描述值和存储位置(例如文字零),但不是从任何东西派生的,其中一个描述堆对象并派生自Object
;因为只有后一种类型可以向上转换为Object
,所以编译器必须创建后一种类型的新堆对象。每次调用(Object)0
都会创建一个新的堆对象,因此==
的两个操作数是不同的对象,每个对象独立地封装Int32
值0。
类Object
没有为equals运算符定义的任何可用重载。因此,编译器将无法使用重载的相等测试运算符,并将回退到使用引用相等性测试。因为==
的两个操作数引用了不同的对象,所以它将报告false
。
第二次比较成功,因为它询问Int32
的一个堆对象实例是否等于另一个。因为该实例知道等于另一个不同实例意味着什么,所以它可以回答true
。
答案 6 :(得分:3)
两种检查都不同。第一个检查身份,第二个检查相等。通常,如果两个术语指向同一个对象,则它们是相同的。这意味着他们是平等的。如果它们的值相同,则两个术语相等。
在编程方面,身份通常会被引用平等所扰乱。如果指向两个术语的指针相等(!),则它们指向的对象完全相同。但是,如果指针不同,它们指向的对象的值仍然可以相等。在C#中,可以使用静态Object.ReferenceEquals
成员检查身份,同时使用非静态Object.Equals
成员检查相等性。由于您将两个整数转换为对象(称为“拳击”,顺便说一句),==
的操作符object
执行第一次检查,默认情况下映射到Object.ReferenceEquals
并检查为了身份。如果您明确地调用非静态Equals
- 成员,则dynamic dispatch会调用Int32.Equals
,以检查是否相等。
两个概念都相似,但不一样。它们最初可能看起来很混乱,但差别很小很重要!想象一下两个人,即“爱丽丝”和“鲍勃”。他们都住在黄色的房子里。基于这样的假设,爱丽丝和鲍勃住在一个区域,房子的颜色不同,他们都可以住在不同的黄色房子里。如果你比较两个家庭你会认识到,它们是完全相同的,因为它们都是黄色的!但是,他们不是共享同一个家庭,因此他们的房子相等,但不是相同的。身份意味着他们住在相同的房子里。
注意:某些语言正在定义===
运算符以检查身份。