首页 > C#中内容相同的string和装箱string,判等为什么时而相等时而不等?

C#中内容相同的string和装箱string,判等为什么时而相等时而不等?

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呢???


而你的三个判等都是stringobject判。string(System.String) 是 object(System.Object) 的派生类,因此这个判等中string降格为object,均遵守object的判等规则,即判断两个引用是否指向同一个实例。

你的三个判等,均不判断字符串内容是否相等。
你的三个判等,均不判断字符串内容是否相等。
你的三个判等,均不判断字符串内容是否相等。
违反直觉,但是符合语言设计。说三遍,一定不要忘。


第一个判等(相等)是因为编译器经过了优化。编译器对于程序中的:

会自动扫描,去重复,并把每一个不重复的字面值,作为字符串创建到内存中一个只读的位置。

当用户程序把一个字面值赋给一个string变量时,事实上只是把这个string指向了内存中字面值的实例,而不是把字符串的内容,真的在内存中新开一块区域拷贝了一遍。

所以此时你的string1string2同时指向了内存中同一个字符串字面值"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的内容相等,那么请使用以下用法之一:

这两个操作都会把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下编译的警告。

【热门文章】
【热门文章】