object a = "1";
object b = "1";
Console.WriteLine(a == b); // returns True
object c = 1;
object d = 1;
Console.WriteLine(c == d); // returns False
上面的代码返回整数和字符串的不同结果。我无法理解为什么。有人可以帮我理解背后的原因吗?
==
(运算符)和ReferenceEquals
(函数)之间有什么区别?
答案 0 :(得分:26)
将整数声明为object
会产生boxing operation。现在它们被装箱,等式运算符执行引用比较,并且引用不相同。然而,string
类型定义了自己的相等运算符并执行值比较(即“我的字符是否与其他字符串的字符相同?”)
编辑:根据@Enigmativity,我错过了两个字符串也被声明为object
的事实。这使得事情稍微复杂一些。我之前关于字符串的陈述在这里是错误的,因为operator==
不是多态的。比较返回true,因为这些字符串是实体的,这意味着它们实际上是同一个对象,因此引用比较返回true。
答案 1 :(得分:13)
虽然Ed S has answered ==
检查引用相等性的点。但是要添加MSDN链接也说同样的事情
对于预定义的值类型,等于运算符(==)返回true,如果 其操作数的值相等,否则为false。以供参考 除了string之外的类型,==如果它的两个操作数引用则返回true 同一个对象。对于字符串类型,==比较的值 字符串。
如果您想要比较对象,那么您可以使用Equals
方法。
另外,当您询问==和referenceEquals之间的区别时,您应该注意==
正在重载并且Equals
会覆盖。
所以,如果你这么说
string x = "ABCD";
string y = 'A' + "BCD"; // ensure it's a different reference
if (x == y) { // evaluates to TRUE
因为用于比较变量x和y的方法是在编译时决定的。字符串是不可变的,因此使用==
重载来支持字符串的值相等没有任何害处。当编译器优化您的字符串文字时,它会发现x
和y
都具有相同的值,因此您只需要一个字符串对象。它是安全的,因为String在C#中是不可变的。
当您使用Equals
时,变量的类型将根据变量x中的实际类型在运行时确定。
object x = "ABCD";
object y = 'A' + "BCD"; // ensure it's a different reference
if (x == y) { // evaluates to FALSE
,而
object x = "ABCD";
object y = 'A' + "BCD"; // ensure it's a different reference
if (x.Equals(y)) { // evaluates to TRUE
您也可以查看 Guidelines for Overriding Equals() and Operator == (C# Programming Guide)
在C#中,有两种不同的等式:引用相等 (也称为身份)和价值平等。价值平等就是 通常理解平等的含义:它意味着两个对象 包含相同的值。 例如,两个值为2的整数 有价值平等。引用相等意味着没有两个 要比较的对象。相反,有两个对象引用和两者 它们指的是同一个对象。
[...]
默认情况下,运算符==测试引用相等性 确定两个引用是否表示相同的对象。 因此,引用类型不必实现operator == in 为了获得这个功能。当一个类型是不可变的,即 实例中包含的数据无法更改, 重载operator ==来比较值的相等而不是引用 平等可能很有用,因为它们可以作为不可变对象 只要它们具有相同的值,它们就被认为是相同的。它不是 好主意在非不可变类型中覆盖operator ==。
答案 2 :(得分:5)
此代码返回false
:
object a = "a";
object b = a + "b";
a = "ab";
Console.WriteLine(a == b); // returns False
此代码返回true
:
object a = "ab";
object b = "ab";
Console.WriteLine(a == b); // returns True
但在这两种情况下a
& b
是" ab"。不同之处在于,对于第二组代码,编译器优化代码并使用相同的字符串。
因此作为对象的字符串正在评估==
作为引用等于。没有区别。
答案 3 :(得分:3)
C#中的==
标记用于表示两个运算符:可重载的等于测试运算符和不可重载的引用等价测试运算符。在为两个操作数定义了相等测试重载的情况下,它将使用前一个操作符;否则,它会尝试使用后者。因为Object
没有定义任何相等测试重载,所以C#将==
标记解释为引用第二个(引用等价)运算符。
示例中的字符串比较相等的原因并不是生成的代码正在检查其内容,而是与字符串文字的实现方式有关。编译程序集时,编译器会构建一个列表,列出其中出现的所有字符串文字;该列表中所有字符串的长度和内容都包含在生成的程序集中的blob中。在每个地方,在代码中使用字符串文字,编译器插入一条指令“加载对* n * th字符串的引用”,并且在生成所有代码之后,编译器在程序集中包含每个字符串文字的字符序列其中包含。加载程序集时,.NET运行时将创建一个String
引用表,为该程序集中定义的所有字符序列生成String
个实例,并将引用存储到新创建的字符串中在表中。由于这一切,将变量设置为字符串文字“George”不会创建新的字符串对象,而是使变量标识一个对象,该对象包含在首次加载代码时创建的六字符序列George
如果编译器和/或运行时碰巧注意到相同的字符序列出现在多个字符串文字中,则可以通过引用String
对象来满足对包含该序列的后续文字的请求。为早期建造。一般来说,代码应该以不关心何时发生这种替换的方式编写。如果文字在源文件中出现多次,编译器几乎肯定会用对同一字符串实例的引用替换所有出现的事件,但是编写良好的代码不应该依赖于它。
在您的示例中,文字"1"
的所有相关用法都出现在同一个文件中,因此被替换为对同一个字符串对象的引用,但完全可能是其他String
个实例包含单个字符1
的可能存在;使用==
运算符将字符串文字“1”与类型为Object
的变量进行比较,该变量标识其中一个字符串将产生false
。
答案 4 :(得分:0)
定义是这样的: 来自String.cs
public static bool operator == (String a, String b) {
return String.Equals(a, b);
Equal方法的定义是:
public static bool Equals(String a, String b) {
if ((Object)a==(Object)b) {
return true;
}
if ((Object)a==null || (Object)b==null) {
return false;
}
if (a.Length != b.Length)
return false;
return EqualsHelper(a, b);
}