.NET对象判等(二)

.NET对象的几种判等,耦合在一起,我尽量在任意一种判等里不涉及其他判等方式。但是Instace.Equals仍然不法避免不使用到Operator ==,所以我把Operator ==作为第三部分内容。

三、Operator==深入本质

默认情况下,Operator==在对引用类型对象判等的本质和Object.ReferenceEquals是相同的即确定指定的变量是否是相同的实例。

当然C#.NET可对Opeartor==进行定义,鄙人认为应该避免自定义Operator==。任意定义将会对使用者对Opeartor==的作用产生混淆。毕竟没有任何逻辑比a=a更有逻辑了。

对于自描述值类型来说如果想使用Operator==进行判等,那么就要对Opeartor==以及Opeartor!=分别进行定义。FCL的大部分值类型都是这样做的比如DateTime、Decimal等。

存在这样的情况Int32、Int64、Byte等值类型并未定义Opeartor==,但是编译器仍然支持以上类型变量直接使用Operator==进行判等。同查阅相关资料得知包括byte、shrot、 int、long、char、float、double、bool、decimal、string、object、dynamic共十二种类型为基元类型。编译器直接支持的数据类型称为基元类型。基元类型直接映射到Framework类库(FCL)中存在的类型。比如在C#中,int直接映射到System.Int32类型。

当两个int类型变量进行判等,首先将两个值压入计算堆栈,CLR通过CEQ指令直接对值进行判等。当然基元类型是支持定义Opeartor的比如Decimal就定义了Opeartor==。

有趣的是,sbyte、ushort、uint、ulong并非基元类型,也未定义Opeartor,但是以上几种类型直接使用Opeartor==判等,CSC编译器仍然能够编译通过。以ushort为例,请看一下代码:

1 static void Main()
2 { 
3       ushort u1=1;
4       ushort u2 = 2;
5       var b = u1 == u2;
6  }

通过ILDASM反编译,得到的IL代码

 1 .method private hidebysig static void  Main() cil managed
 2 {
 3   .entrypoint
 4   // 代码大小       11 (0xb)
 5   .maxstack  2
 6   .locals init (uint16 V_0,
 7            uint16 V_1,
 8            bool V_2)
 9   IL_0000:  nop
10   IL_0001:  ldc.i4.1 //将整数值 1 作为 int32 推送到计算堆栈上。                               
12   IL_0002:  stloc.0  //从计算堆栈的顶部弹出当前值并将其存储到索引 0处的局部变量列表中。 
13   IL_0003:  ldc.i4.2 //将整数值 2 作为 int32 推送到计算堆栈上。
15   IL_0004:  stloc.1  //同上,存储到索引1处的局部变量列表
16   IL_0005:  ldloc.0  //将索引 0 处的局部变量加载到计算堆栈上。
17   IL_0006:  ldloc.1  //同上
18   IL_0007:  ceq      //如果这两个值相等,则将整数值 1 (int32) 推送到计算堆栈上;否则,将 0 (int32) 推送到计算堆栈上。
19   IL_0009:  stloc.2  //同上
20   IL_000a:  ret
21 } // end of method Program::Main

代码中添加了一部分注释,大概的意思就是将ushort隐身的看作int类型,在通过CEQ指令对基元类型进行判等,类似于以下代码:

1 static void Main()
2  { 
3       int i1 = 1;
4       int i2 = 2;
5       var b = i1 == i2;
6  }

关于Instance.Equals将在下一篇文章中讲解。

posted on 2013-02-23 14:39  朝曦  阅读(1220)  评论(6编辑  收藏  举报

导航