这里有一小段代码:
String a = "abc";
Console.WriteLine(((object)a) == ("ab" + "c")); // true
Console.WriteLine(((object)a) == ("ab" + 'c')); // false
为什么?
这里有一小段代码:
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'
则不是,因此不是引用相等的(连接操作在运行时完成)。
请点击这里查看反编译的代码。
我要补充说明的是,Try Roslyn 进行了错误的反编译 :-),甚至 IlSpy 也是如此 :-(
它反编译为:
string expr_05 = "abc"
Console.WriteLine(expr_05 == "abc");
Console.WriteLine(expr_05 == "ab" + 'c');
所以是字符串比较。但至少可以清楚地看到一些字符串在编译时计算出来。
为什么您的代码要执行引用比较?因为您将其中一个成员强制转换为 object ,并且.NET中的
operator == 不是
virtual ,因此必须使用编译器具有的信息在编译时解决它,然后... 取自==运算符
对于预定义值类型,如果其操作数的值相等,则等号运算符(==)返回true,否则返回false。对于除字符串外的引用类型,如果它的两个操作数引用同一个对象,则==返回true。对于字符串类型,==比较字符串的值。
对于编译器而言,
== 运算符的第一个操作数不是
string (因为您进行了强制转换),因此它不属于
string 比较。
有趣的事实:在.NET的CIL级别(汇编语言),使用的操作码是
ceq ,它对基元值类型进行值比较,并对引用类型进行引用比较(因此最终始终进行位比较,对于带NaN的浮点类型有一些例外)。 它不使用“特殊”的
operator == 方法。 这可以在此示例中看到。
其中
Console.WriteLine(a == ("ab" + 'c')); // True
在调用时在编译时解析
call bool [mscorlib]System.String::op_Equality(string, string)
而其他的
==
则很简单
ceq
这解释了为什么Roslyn反编译器表现得“不好”(如IlSpy :(,参见错误报告)... 它看到一个操作码ceq
,没有检查是否需要强制转换来重建正确的比较。Holger问为什么只有两个字符串字面值之间的加法是由编译器完成的... 现在,以非常严格的方式阅读C# 5.0规范,并将C# 5.0规范视为与.NET规范“分开的”(除了C# 5.0对某些类/结构/方法/属性的先决条件等异常情况),我们有:
字符串连接:
string operator +(string x, string y);
string operator +(string x, object y);
string operator +(object x, string y);
这些二元操作符的重载执行字符串连接。如果字符串连接的操作数为null,则替换为空字符串。否则,通过调用从类型对象继承的虚拟 ToString 方法将任何非字符串参数转换为其字符串表示形式。如果 ToString 返回 null,则替换为空字符串。因此,“string + string”、“string + null”、“null + string”的情况都被准确描述,并且它们的结果可以仅使用C#规范的规则“计算”。对于每种其他类型,必须调用虚拟 ToString 方法。在 C# 规范中,任何类型的 virtual ToString 方法的结果都未定义,因此如果编译器“假定”它的结果,它会做错事。例如,一个返回 Yes/No 而不是 True/False 的 System.Boolean.ToString() 版本仍然适用于 C# 规范。
a
转换为 string
,那么两个控制台输出都是 true
。 - Kaz"ab"+"c"
在编译时就被解决了,而 "ab"+'c'
却没有。例如在Java中,两者都是编译时常量,所以为什么在C#中不行... - Holgerstring + null
和 string + string
。string + int
没有被优化。string + bool
也没有。请注意,String.Empty
是一个只读字段,如果使用它,它也不会被优化... "A" + String.Empty
是在运行时完成的。 - xanatos地址不同。如果您想比较字符串字符,请建议使用equals。
"ab" + 'c'
是两种不同的对象类型,它的结果为ab
。 - AStopher