string.Equals(string)和==的原理

时间:2021-01-27 16:16:45
 

  在我写了一篇毫无价值的文章之后,经过进一步研究,补充了这部分,搞明白了为什么会出现上次的结果。最后面灰色字体是上一篇文章,有错误,仅供参考,大家只看黑色字体就可以了。

 

   写完了上一篇文章,我不得不接受批评。很明显,我没有读过《Applied Microsoft .NET Framework Programming》一书,不然就不会进行这样的测试了。而且,测试方法也写得不对。经过事后研究,明白了其中的道理和本质。反思如下:

  经过反编译,.NET“==”是这样实现的:<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

public static bool operator ==(string a, string b)

{

      return string.Equals(a, b);

}

strings.Equals(string, string)的实现如下:

public static bool Equals(string a, string b)

{

      if (a == b)

      {

            return true;

      }

      if ((a != null) && (b != null))

      {

            return a.Equals(b);

      }

      return false;

}

最后string.Equals(string)的实现(通过内部调用实现的,具体怎么实现的就不得而知了):

[MethodImpl(MethodImplOptions.InternalCall)]

public extern bool Equals(string value);

  由此可见, ==先比较了两个对象的引用,如果引用相同直接返回true。如果引用不同就调用了a.Equals(b)。所以,在上面的程序中,所有"67412"都是同一个对象,==也就比Equals快了一步,没有进入string.Equals(string)就返回true了。与"67413"比较的时候,引用不同了,==通过调用string.Equals(string)才返回,所以又多用了一点比较引用的时间。如果两个字符串引用不同内容相同,那么用的时间跟上面返回false的那组测试应该是一样的。如果你以前只知道==是通过Equals实现的,现在你应该知道为什么第一组==Equals快了。

  下面是几条语句的反汇编的结果,也可以看出所有的"67412"都是来自同一个地址:

   string toBeTested = "67412";
00000000  push        ebp 
00000001  mov         ebp,esp
00000003  sub         esp,8
00000006  push        edi 
00000007  push        esi 
00000008  push        ebx 
00000009  xor         esi,esi
0000000b  xor         edi,edi
0000000d  mov         eax,dword ptr ds:[01AE1058h]
00000013  mov         esi,eax
    toBeTested.Equals("67412");
00000015  mov         edx,dword ptr ds:[01AE1058h]
0000001b  mov         ecx,esi
0000001d  cmp         dword ptr [ecx],ecx
0000001f  call        dword ptr ds:[79C126F4h]
00000025  nop             
    result = toBeTested == "67412";
00000026  mov         edx,dword ptr ds:[01AE1058h]
0000002c  mov         ecx,esi
0000002e  call        dword ptr ds:[79C126FCh]
00000034  movzx       ebx,al
00000037  movzx       eax,bl
0000003a  mov         edi,eax
    result = toBeTested.Equals("67413");
0000003c  mov         edx,dword ptr ds:[01AE105Ch]
00000042  mov         ecx,esi
00000044  cmp         dword ptr [ecx],ecx
00000046  call        dword ptr ds:[79C126F4h]
0000004c  movzx       ebx,al
0000004f  movzx       eax,bl
00000052  mov         edi,eax
    result = toBeTested == "67413";
00000054  mov         edx,dword ptr ds:[01AE105Ch]
0000005a  mov         ecx,esi
0000005c  call        dword ptr ds:[79C126FCh]
00000062  movzx       ebx,al
00000065  movzx       eax,bl
00000068  mov         edi,eax
  }
0000006a  nop             
0000006b  pop         ebx 
0000006c  pop         esi 
0000006d  pop         edi 
0000006e  mov         esp,ebp
00000070  pop         ebp 
00000071  ret             

  这回够彻底了吧。真相大白!还有一点没有说就是一位网友提到的字符串池的概念。我还不太了解,就不敢说了。

  我看《Applied Microsoft .NET Framework Programming》去了……同时我也向还没有读过此书又想了解.NET原理的同志们推荐它。

 

附:上一篇文章的内容

  要比较两个字符串是否相等,有两种方法:

string toBeTested = "67412";
bool result;

result = toBeTested.Equals("67413");

result = toBeTested == "67413";

哪一种方法好呢?

测试程序:
   int times = 100000000;
   int start, end;
   int i;
   bool result;
   string toBeTested = "67412";

   start = System.Environment.TickCount;
   for(i=0; i<times; i++)
   {
    result = toBeTested.Equals("67412");
   }
   end = System.Environment.TickCount;
   Console.WriteLine("Equals True Time: " + (end-start)/1000.0 + " Seconds");

   start = System.Environment.TickCount;
   for(i=0; i<times; i++)
   {
    result = toBeTested == "67412";
   }
   end = System.Environment.TickCount;
   Console.WriteLine("== True Time: " + (end-start)/1000.0 + " Seconds");

   start = System.Environment.TickCount;
   for(i=0; i<times; i++)
   {
    result = toBeTested.Equals("67413");
   }
   end = System.Environment.TickCount;
   Console.WriteLine("Equals False Time: " + (end-start)/1000.0 + " Seconds");

   start = System.Environment.TickCount;
   for(i=0; i<times; i++)
   {
    result = toBeTested == "67413";
   }
   end = System.Environment.TickCount;
   Console.WriteLine("== False Time: " + (end-start)/1000.0 + " Seconds");


结果:

Equals True Time: 3.234 Seconds
== True Time: 0.562 Seconds
Equals False Time: 3.391 Seconds
== False Time: 3.891 Seconds

可见当结果为true时,==Equals()快很多;当结果为false时,Equals()略快于==
结论:如果要比较的字符串相同的多,就用==;要比较的字符串中不同的多,就用Equals()