这里有一小段代码:
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
,而将operator==
强制转换为。NET不是virtual
,所以它必须在编译时用编译器所拥有的信息来解决,然后。。。from==操作员
对于预定义的值类型,如果其操作数的值相等,则相等运算符(==)返回true,否则返回false对于字符串以外的引用类型,如果其两个操作数引用同一对象,则==返回true对于字符串类型,==比较字符串的值。
对于编译器来说,==
运算符的第一个操作数不是string
(因为您对其进行了强制转换),因此它不属于string
比较。
有趣的事实:在CIL级别(.NET的汇编语言),使用的操作码是ceq
,它对基元值类型进行值比较,对引用类型进行引用比较(所以最后它总是进行逐位比较,带有NaN的浮点类型除外)。它不使用";特别的";CCD_ 12方法。在这个例子中可以看到
其中
Console.WriteLine(a == ("ab" + 'c')); // True
在对的调用中在编译时被解析
call bool [mscorlib]System.String::op_Equality(string, string)
而其他CCD_ 13只是
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);
binary+运算符的这些重载执行字符串串联。如果字符串串联的操作数为null,则替换空字符串。否则,任何非字符串参数都将通过调用从类型对象继承的虚拟ToString方法转换为其字符串表示。如果ToString返回null,则替换一个空字符串。
因此,string + string
、string + null
、null + string
都被精确地描述了,它们的结果可以是"0";计算的";只使用C#规范的规则。对于其他类型,必须调用virtual ToString
方法。virtual ToString
方法的结果没有为C#规范中的任何类型定义;假定";其结果是它会做一个错误的";事情";。例如a。NET版本的System.Boolean.ToString()
返回Yes
/No
而不是True
/False
对于C#规范来说仍然可以。
地址不相同。如果要比较字符串,建议使用equals。