string string1 = "value";
object string2 = "value";
if (string1 == string2)
Console.WriteLine("==");
else
Console.WriteLine("not eq");
string2 = string2 + "s";
if (string1 == string2)
Console.WriteLine("==");
else
Console.WriteLine("not eq");
string2 = ((string)string2).Remove(((string)string2).Length - 1, 1);
if (string1 == string2)
Console.WriteLine("==");
else
Console.WriteLine("not eq");
最后一个为什么会是not eq呢???
object
的互相判等,表示两个object
是否指向同一个实例,相当于object.ReferenceEquals()
string
的互相判等(被运算符重载)表示两个string
的内容是否相等
而你的三个判等都是string
和object
判。string
(System.String) 是 object
(System.Object) 的派生类,因此这个判等中string
降格为object
,均遵守object
的判等规则,即判断两个引用是否指向同一个实例。
你的三个判等,均不判断字符串内容是否相等。
你的三个判等,均不判断字符串内容是否相等。
你的三个判等,均不判断字符串内容是否相等。
违反直觉,但是符合语言设计。说三遍,一定不要忘。
第一个判等(相等)是因为编译器经过了优化。编译器对于程序中的:
字符串字面值(string literal),即直接写明的字符串
以及无需运行时计算,编译时就可以直接推断出来,可以等同于字符串字面值的表达式(例如
"a" + "b"
这样的)
会自动扫描,去重复,并把每一个不重复的字面值,作为字符串创建到内存中一个只读的位置。
当用户程序把一个字面值赋给一个string
变量时,事实上只是把这个string
指向了内存中字面值的实例,而不是把字符串的内容,真的在内存中新开一块区域拷贝了一遍。
所以此时你的string1
和string2
同时指向了内存中同一个字符串字面值"value"
的实例,判等结果相等。
注意:字符串字面值是不可写入的。但这并不妨碍
string
被赋了一个字符串字面值之后,后续再进行任何的读写操作。因为
string
会延迟到需要写入的最晚时刻,才在内存中开辟一块新区域,把字符串字面值拷贝过去,从而允许各种写入操作修改其内容。即,如果你的s字符串赋了一个字符串字面值,并且保持只读不写,那么就不会有任何拷贝行为发生。这个延迟拷贝的特性在很多编程语言中都是很常见的。
第二个相等(不等)虽说是自然的,但明确概念:判等不等的直接理由,并不是因为你的字符串内容不一样!
string2 = string2 + "s"
这一步,等同于object = object(string) + string
。则赋值表达式右侧,按具体类型string
的相加规则办理,object
拆箱。
此时相当于一个字符串变量和一个字符串字面值相加,这个相加必然是编译期不能推断的,所以必然在内存中开辟一个新的区域,存储新的字符串值。
此时这个内存中新开出的引用赋给了string2
之后,string2
的指向发生了变化,不再指向内存中原来存储字符串字面值"value"
的实例了。这才是第二个判等不等的直接原因。
在理解了前两步的基础之上,再审查第三个,我们就会发现这个在本质上是一样的。
赋值语句是object = (object强转的)string.Remove(int, int)
。注意string.Remove()
函数会新产生一个字符串实例,存储删除后所得的新字符串,并返回给调用者。
即,本质上仍然是:string2
的指向发生了变化,不再指向内存中原来存储字符串字面值"value"
的实例了。这也是第三个判等不等的直接原因。
注意我们一直遵守的是object
的判等规则。即,判等的时候字符串的内容是否相等,不在我们的考虑范围内。请注意这个违反直觉,但是符合语言设计的地方。
如果你确实需要判断装箱string
和一般string
的内容相等,那么请使用以下用法之一:
强转:
(string)myObject == myString
字符串判等的方法:
myString.Equals(myObject)
这两个操作都会把object
拆箱成string
,请注意拆箱错误可能引发的异常。
既然有人回答了,我就不说了。题主你看到这个了么?
str.cs(11,7): warning CS0253: Possible unintended reference comparison. Consider casting the right side expression to type `string' to get value comparison
str.cs(17,7): warning CS0253: Possible unintended reference comparison. Consider casting the right side expression to type `string' to get value comparison
str.cs(25,7): warning CS0253: Possible unintended reference comparison. Consider casting the right side expression to type `string' to get value comparison
我在linux下编译的警告。