字符串比较==只能工作,因为字符串是不可变的吗?

m.e*_*son 13 .net c# string

在比较两个字符串及其变量时,我有一个想法:

string str1 = "foofoo";
string strFoo = "foo";
string str2 = strFoo + strFoo;

// Even thought str1 and str2 reference 2 different
//objects the following assertion is true.

Debug.Assert(str1 == str2);
Run Code Online (Sandbox Code Playgroud)

这纯粹是因为.NET运行时识别字符串的值是相同的,因为字符串是不可变的使得引用str2等于str1

所以,当我们这样做str1 == str2,我们其实比较参考,并不值?我原本以为这是语法糖的产物,但我是不正确的?

我写的任何不准确之处?

Dav*_*haw 14

答案在C#Spec§7.10.7中

字符串相等运算符比较字符串值而不是字符串引用.当两个单独的字符串实例包含完全相同的字符序列时,字符串的值相等,但引用不同.如§7.10.6中所述,引用类型相等运算符可用于比较字符串引用而不是字符串值.

  • 注意`string str2 ="foo"+"foo";`与`string strFoo ="foo"不同; string str2 = strFoo + strFoo;`前一种情况,编译器将变成编译时"foofoo"常量.后一种情况,编译器生成调用`String.Concat`的指令.OP的代码中的引用将不相同,因此对实习的归属具有误导性.(*当然,不同的编译器和不同的构建可能会观察到不同的结果.*) (3认同)
  • 不适用,因为他比较相同的字符串trice - 作为编译时间常量实现. (2认同)

Chr*_*ain 10

没有.

==有效,因为String类重载==运算符等效于Equals方法.

来自Reflector:

[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public static bool operator ==(string a, string b)
{
    return Equals(a, b);
}
Run Code Online (Sandbox Code Playgroud)


Mag*_*nus 7

实际上,String.Equals首先检查它是否是相同的参考,如果没有比较内容.

  • @EricJ.但是如果它们确实具有相同的内存地址,那么**必须**具有相同的内容(毕竟它是*相同的*实例). (3认同)

Bri*_*sen 7

如果我们看一下jitted代码,我们会看到它str2是使用组装的String.Concat,并且它实际上与它的引用不同str1.我们还将看到比较是使用完成的Equals.换句话说,断言在字符串包含相同字符时传递.

这段代码

static void Main(string[] args)
{
    string str1 = "foofoo";
    string strFoo = "foo";
    string str2 = strFoo + strFoo;
    Console.WriteLine(str1 == str2);
    Debugger.Break();
}
Run Code Online (Sandbox Code Playgroud)

是否适合(请向侧面滚动以查看评论)

C:\dev\sandbox\cs-console\Program.cs @ 22:
00340070 55              push    ebp
00340071 8bec            mov     ebp,esp
00340073 56              push    esi
00340074 8b3530206003    mov     esi,dword ptr ds:[3602030h] ("foofoo")  <-- Note address of "foofoo"

C:\dev\sandbox\cs-console\Program.cs @ 23:
0034007a 8b0d34206003    mov     ecx,dword ptr ds:[3602034h] ("foo")  <-- Note different address for "foo"

C:\dev\sandbox\cs-console\Program.cs @ 24:
00340080 8bd1            mov     edx,ecx
00340082 e81977fe6c      call    mscorlib_ni+0x2b77a0 (6d3277a0)     (System.String.Concat(System.String, System.String), mdToken: 0600035f)  <-- Call String.Concat to assemble str2
00340087 8bd0            mov     edx,eax
00340089 8bce            mov     ecx,esi
0034008b e870ebfd6c      call    mscorlib_ni+0x2aec00 (6d31ec00)     (System.String.Equals(System.String, System.String), mdToken: 060002d2)  <-- Compare using String.Equals
00340090 0fb6f0          movzx   esi,al
00340093 e83870f86c      call    mscorlib_ni+0x2570d0 (6d2c70d0) (System.Console.get_Out(), mdToken: 060008fd)
00340098 8bc8            mov     ecx,eax
0034009a 8bd6            mov     edx,esi
0034009c 8b01            mov     eax,dword ptr [ecx]
0034009e 8b4038          mov     eax,dword ptr [eax+38h]
003400a1 ff5010          call    dword ptr [eax+10h]

C:\dev\sandbox\cs-console\Program.cs @ 28:
003400a4 e87775596d      call    mscorlib_ni+0x867620 (6d8d7620) (System.Diagnostics.Debugger.Break(), mdToken: 0600239a)

C:\dev\sandbox\cs-console\Program.cs @ 29:
>>> 003400a9 5e              pop     esi
003400aa 5d              pop     ebp
003400ab c3              ret
Run Code Online (Sandbox Code Playgroud)