为什么(对象)0 ==(对象)0不同于((对象)0).Equals((object)0)?

时间:2013-12-17 18:44:27

标签: c# .net

为什么以下表达式不同?

[1]  (object)0 == (object)0 //false
[2]  ((object)0).Equals((object)0) // true

实际上,我完全理解[1]因为.NET运行时可能会box整数并开始比较引用。但为什么[2]会有所不同?

7 个答案:

答案 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转发为ObjectInt32,与所有值类型一样,实际上代表两种类型,其中一种描述值和存储位置(例如文字零),但不是从任何东西派生的,其中一个描述堆对象并派生自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,以检查是否相等。

两个概念都相似,但不一样。它们最初可能看起来很混乱,但差别很小很重要!想象一下两个人,即“爱丽丝”和“鲍勃”。他们都住在黄色的房子里。基于这样的假设,爱丽丝和鲍勃住在一个区域,房子的颜色不同,他们都可以住在不同的黄色房子里。如果你比较两个家庭你会认识到,它们是完全相同的,因为它们都是黄色的!但是,他们不是共享同一个家庭,因此他们的房子相等,但不是相同的。身份意味着他们住在相同的房子里。

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