试图理解带对象的==运算符

时间:2014-08-20 04:53:26

标签: c#

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(函数)之间有什么区别?

5 个答案:

答案 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的方法是在编译时决定的。字符串是不可变的,因此使用==重载来支持字符串的值相等没有任何害处。当编译器优化您的字符串文字时,它会发现xy都具有相同的值,因此您只需要一个字符串对象。它是安全的,因为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);
        }