考虑下面这段代码。
object str = new string(new char[] { 't', 'e', 's', 't' });
object str1 = new string(new char[] { 't', 'e', 's', 't' });
Console.WriteLine(str==str1); // false
Console.WriteLine(str.Equals(str1)); // true
我理解在这里工作的相等运算符,因为我们已经隐式地转换为对象,等于运算符正在检查两者的引用是否相等并返回false。
但我对第二个问题感到困惑,返回true看起来它正在调用String类型提供的Equals覆盖实现,并且如果它们相等则检查字符串的内容。
我的问题是它为什么不检查运算符的内容相等性,它们的实际类型是字符串而不是对象。对吗?
虽然以下代码输出两者:
object str = "test";
object str1 = "test";
Console.WriteLine(str==str1); // true
Console.WriteLine(str.Equals(str1)); // true
答案 0 :(得分:33)
使用:
Console.WriteLine(str==str1); // false
确定在编译时使用哪个C#预定义(正式)重载operator ==
。由于str
和str1
声明为object
,因此选择了重载operator ==(object, object)
。这是在编译时修复的。仅仅因为实际的运行时类型更具体,那就不会改变。如果要在运行时进行绑定,请改用Console.WriteLine((dynamic)str == (dynamic)str1); /* true */
。
使用:
Console.WriteLine(str.Equals(str1)); // true
您在object
上调用 虚拟 方法。虚拟意味着它将在运行时转到与override
相关的任何内容。类System.String
具有覆盖功能,由于str
将具有运行时类型System.String
,因此“虚拟调度”将使用覆盖。
关于问题底部的补充:由于字符串实习,情况有所不同。字符串实习是一种优化,其中相同的物理实例用于其值相同的形式上不同的字符串。当您有两个字符串,其值在源代码中给出时,字符串实习将“优化”并对相同的实例进行两次引用。这通常是无害的,因为字符串保证不可变。因此,通常您不关心它是相同的实例还是具有相同值的另一个实例。但在你的例子中,我们可以“揭示”实习生。
注意:字符串实习与您的原始问题无关。只有在您的问题中添加了新示例后,字符串实习才变得相关。
答案 1 :(得分:3)
当在类型为object的表达式上使用==时,它将解析为System.Object.ReferenceEquals。
Equals只是一个虚方法,并且表现如此,因此将使用被覆盖的版本(对于字符串类型,它将比较内容)。
答案 2 :(得分:2)
这是因为字符串实习;当你写:
object str = "test";
object str1 = "test";
Console.WriteLine(str==str1);
这可以正常工作,因为编译器在内部并静默地将两个字符串复制到一个位置,因此两个指针实际上将指向相同的对象。
如果你从一个字符数组中创建一个字符串,编译器就不够聪明,无法理解你的意图,而且它与上面的内容相同,所以,作为一个字符串引用类型,它们& #39;有效地在内存中有两个不同的对象。
看一下这篇文章:https://blogs.msdn.microsoft.com/ericlippert/2009/09/28/string-interning-and-string-empty/
等于方法在字符串中被覆盖,因此它将字符串的实际内容而非地址进行比较为 == ( ReferenceEquals )在您的情况下,因为类型是对象。
答案 3 :(得分:1)
我认为这是因为String
==
operator仅将string
类型作为参数,而.Equals
method需要object
1}}类型作为参数。
由于字符串==
仅将string
类型作为参数,因此重载决策选择要用于比较的对象==
运算符。
答案 4 :(得分:-3)
对String.Equals
方法的帮助将此作为注释:
此方法执行序数(区分大小写和 文化不敏感的比较。
因此,通过char检查字符串char来完成比较,从而得到true。