Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么这两个字符串比较会返回不同的结果?_C#_String_Reference_Pre Compilation - Fatal编程技术网

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”+字符串。空的
在运行时完成。