为什么这两个字符串比较return不同的结果?
Why do these two string comparisons return different results?
这是一小段代码:
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
For predefined value types, the equality operator (==) returns true if the values of its operands are equal, false otherwise. For reference types other than string, == returns true if its two operands refer to the same object. For the string type, == compares the values of the strings.
对于编译器,==
运算符的第一个操作数不是 string
(因为你强制转换了它),所以它不属于 string
比较.
有趣的事实:在 CIL 级别(.NET 的汇编语言),使用的操作码是 ceq
,它对原始值类型进行值比较,对引用类型进行引用比较(所以在end 它总是进行逐位比较,但带有 NaN 的浮点类型除外)。它不使用“特殊”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 对某些 classes/structs/methods/properties/... 的先决条件除外),我们有:
String concatenation:
string operator +(string x, string y);
string operator +(string x, object y);
string operator +(object x, string y);
These overloads of the binary + operator perform string concatenation. If an operand of string concatenation is null, an empty string is substituted. Otherwise, any non-string argument is converted to its string representation by invoking the virtual ToString method inherited from type object. If ToString returns null, an empty string is substituted.
因此,string + string
、string + null
、null + string
的情况都被精确地描述了,并且它们的结果可以仅使用C#规范的规则来“计算”。对于所有其他类型,必须调用 virtual ToString
方法。 virtual ToString
方法的结果在 C# 规范中没有为任何类型定义,所以如果编译器“假定”它的结果,它就会做错“事”。例如,具有 System.Boolean.ToString()
且返回 Yes
/No
而不是 True
/False
的 .NET 版本对于 C# 规范来说仍然可以。
地址不一样。如果要比较字符串字符,建议使用equals。
这是一小段代码:
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
For predefined value types, the equality operator (==) returns true if the values of its operands are equal, false otherwise. For reference types other than string, == returns true if its two operands refer to the same object. For the string type, == compares the values of the strings.
对于编译器,==
运算符的第一个操作数不是 string
(因为你强制转换了它),所以它不属于 string
比较.
有趣的事实:在 CIL 级别(.NET 的汇编语言),使用的操作码是 ceq
,它对原始值类型进行值比较,对引用类型进行引用比较(所以在end 它总是进行逐位比较,但带有 NaN 的浮点类型除外)。它不使用“特殊”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 对某些 classes/structs/methods/properties/... 的先决条件除外),我们有:
String concatenation:
string operator +(string x, string y); string operator +(string x, object y); string operator +(object x, string y);
These overloads of the binary + operator perform string concatenation. If an operand of string concatenation is null, an empty string is substituted. Otherwise, any non-string argument is converted to its string representation by invoking the virtual ToString method inherited from type object. If ToString returns null, an empty string is substituted.
因此,string + string
、string + null
、null + string
的情况都被精确地描述了,并且它们的结果可以仅使用C#规范的规则来“计算”。对于所有其他类型,必须调用 virtual ToString
方法。 virtual ToString
方法的结果在 C# 规范中没有为任何类型定义,所以如果编译器“假定”它的结果,它就会做错“事”。例如,具有 System.Boolean.ToString()
且返回 Yes
/No
而不是 True
/False
的 .NET 版本对于 C# 规范来说仍然可以。
地址不一样。如果要比较字符串字符,建议使用equals。