C# 为什么这两个字符串比较会返回不同的结果?
下面是一小段代码:C# 为什么这两个字符串比较会返回不同的结果?,c#,string,reference,pre-compilation,C#,String,Reference,Pre Compilation,下面是一小段代码: String a = "abc"; Console.WriteLine(((object)a) == ("ab" + "c")); // true Console.WriteLine(((object)a) == ("ab" + 'c')); // false 为什么? 因为==正在进行引用比较。在C#编译器中,编译时已知的所有“相等”字符串都被“分组”在一起,以便 string a = "abc"; string b = "abc&qu
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');
所以字符串比较。但至少可以清楚地看到一些字符串是在编译时计算的
为什么您的代码要进行引用比较?因为您正在将两个成员中的一个强制转换为对象
,而.NET中的运算符==
不是虚拟的
,所以必须在编译时使用编译器拥有的信息对其进行解析,然后…从
对于预定义的值类型,如果其操作数的值相等,则相等运算符(=)返回true,否则返回false。对于字符串以外的引用类型,如果其两个操作数引用同一对象,则==返回true。对于字符串类型,则==比较字符串的值
对于编译器来说,==
运算符的第一个操作数不是字符串(因为是您铸造的),因此它不属于字符串
比较
有趣的事实:在CIL级别(.NET的汇编语言),使用的操作码是ceq
,它对原语值类型进行值比较,对引用类型进行引用比较(因此最后它总是进行逐位比较,对带有NaN的浮点类型有一些例外)。它不使用“特殊”operator==
方法。可以在下面的
在哪里
Console.WriteLine(a == ("ab" + 'c')); // True
在编译时调用中解析
call bool [mscorlib]System.String::op_Equality(string, string)
而另一个=
只是
ceq
这就解释了为什么Roslyn反编译器工作“不好”(正如IlSpy:-(,请参阅)…它看到一个操作码ceq
,并且不检查是否需要强制转换来重建正确的比较
霍尔格问,为什么只有两个字符串文本之间的加法是由编译器完成的……现在,以一种非常严格的方式阅读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,则空字符串为substring塔特
因此,案例string+string
,string+null
,null+string
都被精确描述,并且它们的结果可以“计算”通过仅使用C规范的规则。对于每一种其他类型,必须调用虚拟ToString
方法。C规范中没有为任何类型定义虚拟ToString
方法的结果,因此如果编译器“假定”其结果,它将做错误的“事情”。例如,如果.NET版本的System.Boolean.ToString()
返回Yes
/No
,而不是True
/False
,则对于C规范仍然可以。地址不相同。如果要比较字符串字符,建议使用等于。
是两种不同的对象类型,其计算结果为ab
。如果您可以添加字符串和字符,则结果为字符串“abc”
。有关与您注意到的现象密切相关的一些问题,请参阅我的文章。您应该提到为什么还要进行参考比较以使此答案完美。如果您将a
转换为字符串
,两个控制台输出都是true
,唯一剩下的问题是为什么“ab”+“c”
在编译时求解,而则为“ab”+“c”
不是。例如,在Java中,这两个都是编译时常量,所以为什么不在c#…@Holger中,他们可能没有想到它。从我做的一些测试中,我认为他们只优化了string+null
和string+string
string+int
没有优化。也不是string+bool
。请注意string.Empty
是一个只读字段,因此如果使用也不会优化…“a”+字符串。空的
在运行时完成。