昨天上课,提到了string的==和Equals的问题,当时没有实验条件,讨论也就停留在表面层次。今天调试一下,得到如下结果。
private void Button7_Click(object sender, EventArgs e)
{
string a;
string b;
a = "hello";
b = "hello";
//第一步,测试 a==b
/*
a = "hello";
00000033 8B 05 DC 30 3E 02 mov eax,dword ptr ds:[023E30DCh]
00000039 8B F8 mov edi,eax
b = "hello";
0000003b 8B 05 DC 30 3E 02 mov eax,dword ptr ds:[023E30DCh]
00000041 8B D8 mov ebx,eax
* 这里编译器做了优化,无论比较值还是比较地址,都是相等的,因此,此测试没有什么意义
*/
if (a == b)
{
MessageBox.Show("a==b");
}
else
{
MessageBox.Show("a!=b");
}
//第二步,绕开编译器的优化,测试 a==b
string c = "hello world";
/*
00000089 8B FE mov edi,esi
0000008b 6A 05 push 5
0000008d 8B 4D B4 mov ecx,dword ptr [ebp-4Ch]
00000090 33 D2 xor edx,edx
00000092 39 09 cmp dword ptr [ecx],ecx
00000094 E8 AB F7 FB 77 call 77FBF844 //SubString
00000099 89 45 AC mov dword ptr [ebp-54h],eax
0000009c 8B 55 AC mov edx,dword ptr [ebp-54h]
0000009f 8B CF mov ecx,edi
000000a1 E8 22 2D FF 77 call 77FF2DC8 //比较过程,下面有详细描述
000000a6 8B F8 mov edi,eax
000000a8 85 FF test edi,edi
000000aa 0F 94 C0 sete al
000000ad 0F B6 C0 movzx eax,al
000000b0 8B D8 mov ebx,eax
000000b2 85 DB test ebx,ebx
000000b4 75 11 jne 000000C7
*
Call Stack
* > mscorlib.dll!string.EqualsHelper(string strA, string strB = "hello") + 0x20 bytes
mscorlib.dll!string.Equals(string a, string b) + 0x1a bytes
mscorlib.dll!string.operator ==(string a, string b) + 0x5 bytes
从这里可以看到 “==”已经被override了
这里可以看到,是根据字符串内容比较的,不是比较地址
0000007d 8B 02 mov eax,dword ptr [edx]
0000007f 3B 01 cmp eax,dword ptr [ecx]
00000081 75 0D jne 00000090
*/
if (a == c.Substring(0, 5))
{
MessageBox.Show("a == c.Substring(0, 5)");
}
else
{
MessageBox.Show("a != c.Substring(0, 5)");
}
}
private void button8_Click(object sender, EventArgs e)
{
string a = "hello";
string b = null;
/*
* Call Stack
> mscorlib.dll!string.EqualsHelper(string strA = "hello", string strB = "hello")
mscorlib.dll!string.Equals(string value) + 0x10 bytes
*/
if (a.Equals("hello"))
{
MessageBox.Show("a.Equals(\"hello\")");
}
else
{
MessageBox.Show("not a.Equals(\"hello\")");
}
if (a.Equals(null))
{
MessageBox.Show("a.Equals(null)");
}
else
{
MessageBox.Show("not a.Equals(null)");
}
if (a.Equals(b))//Get an exception in 2005, not equal in Orcas
{
MessageBox.Show("a.Equals(b)");
}
else
{
MessageBox.Show("not a.Equals(b)");
}
if (((string)null).Equals(null))//Get an exception
{
MessageBox.Show("null.Equals(null)");
}
else
{
MessageBox.Show("not null.Equals(null)");
}
if (b.Equals(b))//Get an exception
{
MessageBox.Show("b.Equals(b)");
}
else
{
MessageBox.Show("not b.Equals(b)");
}
}
结论,两者没有本质区别,最终都是调用mscorlib.dll!string.EqualsHelper
细微的差别还是有的,那就是调用Equals的类不能为空。貌似这句话是废话,hoho.
从效率上讲,==多调用一层函数,充其量是多了两个move,和一个call,可以忽略不计。
不过在2005下调用Equals时,参数不能为null,否则会抛异常,没跟踪,记住就可以了,具体原因自己看汇编吧。
以上列出的是Orcas的编译结果。