为什么以下表达式不同?
[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因此它们是相等的
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)
C#运算符使用标记==来表示两个不同的运算符:静态可重载的比较运算符和不可重载的引用比较运算符.遇到==令牌时,它首先检查是否存在适用于操作数类型的任何相等测试重载.如果是这样,它将调用该重载.否则,它将检查类型是否适用于引用比较运算符.如果是这样,它将使用该运算符.如果两个运算符都不适用于操作数类型,则编译将失败.
代码(Object)0不只是upcast Int32to Object:Int32和所有值类型一样,实际上代表两种类型,其中一种描述值和存储位置(例如文字零),但不是从任何东西派生的,其中一种描述堆对象并派生自Object; 因为只有后一种类型可以向上转换Object,编译器必须创建后一种类型的新堆对象.每次调用(Object)0都会创建一个新的堆对象,因此两个操作数==是不同的对象,每个对象独立地封装Int32值0.
该类Object没有为equals运算符定义的任何可用重载.因此,编译器将无法使用重载的相等测试运算符,并将回退到使用引用相等性测试.因为两个操作数==引用不同的对象,所以会报告false.第二个比较成功,因为它询问一个堆对象实例Int32它是否等于另一个.因为该实例知道等于另一个不同实例意味着什么,所以它可以回答true.