这是一小段代码:

String a = "abc";

Console.WriteLine(((object)a) == ("ab" + "c")); // true
Console.WriteLine(((object)a) == ("ab" + 'c')); // false

为什么 ?

最佳答案

因为==正在做引用比较。使用C#编译器,将在编译时已知的所有“相等”字符串“分组”在一起,以便

string a = "abc";
string b = "abc";
将指向相同的“abc”字符串。因此,它们将在参照上相等。
现在,("ab" + "c")在编译时简化为"abc",而"ab" + 'c'不简化,因此引用不相等(串联操作在运行时完成)。
参见反编译的代码here
我还要补充一点,Try Roslyn进行了错误的反编译:-)甚至IlSpy :-(
它反编译为:
string expr_05 = "abc"
Console.WriteLine(expr_05 == "abc");
Console.WriteLine(expr_05 == "ab" + 'c');
所以字符串比较。但是至少可以清楚地看到一些字符串是在编译时计算出来的事实。
为什么您的代码进行引用比较?因为您要将两个成员之一转换为object,并且.NET中的operator==不是virtual,所以必须在编译时使用编译器具有的信息进行解析,然后从== Operator中进行解析。

对于编译器,==运算符的第一个操作数不是string(因为您已将其强制转换),因此它不属于string比较。
有趣的事实:在CIL级别(.NET的汇编语言)上,使用的操作码是ceq,它对原始值类型进行值比较,而对引用类型进行引用比较(因此最终,它总是逐位进行比较,但使用NaN的float类型除外)。它不使用“特殊” operator==方法。可以在此example中看到
在哪里
Console.WriteLine(a == ("ab" + 'c')); // True
在调用时在编译时解决
call bool [mscorlib]System.String::op_Equality(string, string)
而其他==只是
ceq
这就解释了为什么Roslyn反编译器会“非常糟糕”地工作(如IlSpy :-(,请参阅bug report)...。它看到一个操作码ceq,并且不检查是否需要强制转换来重建正确的比较。
Holger问为什么编译器只在两个字符串文字之间进行加法运算...现在,以非常严格的方式阅读C#5.0规范,并考虑将C#5.0规范与.NET规范“分开”(使用C#5.0对于某些类/结构/方法/属性/...的先决条件的异常(exception),我们有:

因此,精确描述了string + stringstring + nullnull + string的情况,并且仅使用C#规范的规则就可以“计算”它们的结果。对于其他所有类型,必须调用virtual ToString方法。在C#规范中,没有为任何类型定义virtual ToString方法的结果,因此,如果编译器“假定”其结果,则会执行错误的“操作”。例如,对于C#规范,具有System.Boolean.ToString()返回Yes/No而不是True/False的.NET版本仍然可以。

关于c# - 为什么这两个字符串比较返回不同的结果?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29516327/

10-11 19:24
查看更多