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

And*_*ena 117 .net c#

为什么以下表达式不同?

[1]  (object)0 == (object)0 //false
[2]  ((object)0).Equals((object)0) // true
Run Code Online (Sandbox Code Playgroud)

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

Jar*_*Par 151

调用行为不同的原因是它们绑定到非常不同的方法.

==案例将绑定到静态引用相等运算符.int创建了2个独立的盒装值,因此它们不是相同的参考.

在第二种情况下,您绑定到实例方法Object.Equals.这是一个虚拟方法,它将过滤到Int32.Equals这个并检查一个盒装整数.两个整数值都是0因此它们是相等的

  • @ 280Z28是不是因为编译器内联呢? (8认同)
  • C#语言规范第7.10.6节说:_预定义的引用类型相等运算符是:`bool operator ==(object x,object y);``bool operator!=(object x,object y);`运算符返回比较两个引用的相等或不相等的结果.不要求使用方法`System.Object.ReferenceEquals`来确定结果.至@markmnl:不,C#编译器不内联,这是抖动有时会发生的事情(但在这种情况下不是).所以280Z28是正确的`ReferenceEquals`方法实际上并没有使用. (6认同)

Tho*_*que 26

当您将int值0(或任何其他值类型)强制转换为时object,该值将被加框.每个强制转换object生成一个不同的框(即不同的对象实例).该类型的==运算符object执行引用比较,因此它返回false,因为左侧和右侧不是同一个实例.

另一方面,当您使用Equals虚拟方法时,它使用实际盒装类型的实现,即Int32.Equals返回true,因为两个对象具有相同的值.


Ser*_*rvy 18

==作为静态的运算符不是虚拟的.它将运行object类定义的确切代码(`对象是操作数的编译时类型),它将执行引用比较,而不管任一对象的运行时类型.

Equals方法是一种虚拟实例方法.它将运行在(第一个)对象的实际运行时类型中定义的代码,而不是object类中的代码.在这种情况下,对象是一个int,因此它将执行值比较,因为这是int类型为其Equals方法定义的内容.


SLa*_*aks 13

Equals()方法是虚拟的.
因此,它总是调用具体实现,即使在调用callsite时也是如此object. int覆盖Equals()以按值进行比较,因此您可以进行值比较.


小智 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
Run Code Online (Sandbox Code Playgroud)


sup*_*cat 9

C#运算符使用标记==来表示两个不同的运算符:静态可重载的比较运算符和不可重载的引用比较运算符.遇到==令牌时,它首先检查是否存在适用于操作数类型的任何相等测试重载.如果是这样,它将调用该重载.否则,它将检查类型是否适用于引用比较运算符.如果是这样,它将使用该运算符.如果两个运算符都不适用于操作数类型,则编译将失败.

代码(Object)0不只是upcast Int32to Object:Int32和所有值类型一样,实际上代表两种类型,其中一种描述值和存储位置(例如文字零),但不是从任何东西派生的,其中一种描述堆对象并派生自Object; 因为只有后一种类型可以向上转换Object,编译器必须创建后一种类型的新堆对象.每次调用(Object)0都会创建一个新的堆对象,因此两个操作数==是不同的对象,每个对象独立地封装Int32值0.

该类Object没有为equals运算符定义的任何可用重载.因此,编译器将无法使用重载的相等测试运算符,并将回退到使用引用相等性测试.因为两个操作数==引用不同的对象,所以会报告false.第二个比较成功,因为它询问一个堆对象实例Int32它是否等于另一个.因为该实例知道等于另一个不同实例意味着什么,所以它可以回答true.