.NET对象判等(一)
对于一般的对象来说有判断是否和另一个对象是否相等,有四种方式。
1、Object.ReferenceEquals(static)
2、Object.Equals(static)
3、Instance.Equals
4、Operator ==
一、ReferenceEquals追本溯源
MSDN官方解释:确定指定的 Object 实例是否是相同的实例。
尽管MSDN的解释很简练,到位.但是我仍然通过ILDASM,.NET Reflector 来查看一下ReferenceEquals的实现方式.
.method public hidebysig static bool ReferenceEquals(object objA, object objB) cil managed { .custom instance void System.Runtime.ConstrainedExecution.ReliabilityContractAttribute::.ctor(valuetype System.Runtime.ConstrainedExecution.Consistency, valuetype System.Runtime.ConstrainedExecution.Cer) = ( 01 00 03 00 00 00 02 00 00 00 00 00 ) // 代码大小 5 (0x5) .maxstack 8 IL_0000: ldarg.0 //将索引为 0 的参数加载到计算堆栈上。 IL_0001: ldarg.1 //将索引为 1 的参数加载到计算堆栈上。 IL_0002: ceq IL_0004: ret } // end of method Object::ReferenceEquals
指令CEQ的MSDN官方解释是:比较两个值。如果这两个值相等,则将整数值 1 (int32) 推送到计算堆栈上;否则,将 0 (int32) 推送到计算堆栈上。
这里的“值”实在是大可商榷,据鄙人目测是实例存储在托管堆上的地址,即实例引用(指针)的实际值。
值得注意的是使用Object.ReferenceEquals对值类型变量进行判等,Reshaper会做出提示:'Object.ReferenceEquals‘ 总是返回False
实际上比较两个值类型变量实际与通过此方法对引用类型变量判等是大同小异的,首先看一下ReferenceEqual的方法签名及方法体,如下:
1 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 2 3 public static bool ReferenceEquals(object objA, object objB) 4 { 5 return (objA == objB); 6 }
虽然传入的是值类型变量,但方法体内操作的是引用类型变量,在传参的过程中,CLR对a和b分别进行了封装,获得了存储在GC堆上的两个实例objA和objB,这时候再套用Object.ReferenceEquals对引用变量判等的就可以了。
二、Static Object.Equals
通过.NET Reflector获得Object Equals的实现Code:
1 public static bool Equals(object objA, object objB) 2 { 3 return ((objA == objB) || (((objA != null) && (objB != null)) && objA.Equals(objB))); 4 }
对于Object.Equals我不想讨论过多,因为它把大部分工作都托管给了Operator ==以及Instance.Equals。同时Object.Equals提供了一种良好的对象判等方式。