C#中==运算符和Equals()方法的区别?

==Equals()之间的区别是什么? 我知道==用于比较运算符和Equals()方法用于比较string的内容。所以我试过

 // first example string s1 = "a"; string s2 = "a"; Console.Write(a.Equals(s2)); // returns true, but if I assign "b" to s2, // then result will be false // second example string s1 ="a"; string s2 ="a"; Console.Write(s1 == s2); // returns true 

怎么会这样? 两者都是不同的对象引用。 假设我们认为这些是参考。 但我试着这样使用

 string s1 = new string("ab"); string s2 = new string("ab"); 

我收到编译时错误,无法将字符串转换为char

有几件事正在发生。 首先,在这个例子中:

 string s1 = "a"; string s2 = "a"; Console.WriteLine(s1 == s2); 

你声称:

两者都是不同的对象参考。

由于字符串实习,这不是真的。 s1s2是对同一对象的引用。 C#规范保证 – 从C#4规范的2.4.4.5节:

当根据字符串相等运算符(第7.10.7节)等效的两个或多个字符串文字出现在同一程序中时,这些字符串文字引用相同的字符串实例。

因此,在这种特殊情况下,即使您打印object.ReferenceEquals(s1, s2) ,或者如果您使用与==的真实参考标识比较,您仍然会得到“true”:

 object s1 = "a"; object s2 = "a"; Console.WriteLine(s1 == s2); // Still prints True due to string literal interning 

但是,即使这些对单独对象的引用, ==也会因string重载 。 重载是编译时的决定 – 要使用的实现取决于操作数的编译时类型。 例如:

 string a = new string('x', 1); string b = new string('x', 1); Console.WriteLine(a == b); // Uses string's implementation, prints True object c = a; object d = b; Console.WriteLine(c == d); // Reference identity comparison, prints False 

将它与作为虚方法的object.Equals(object)进行比较。 碰巧, String 也会重载此方法,但重要的是它会覆盖它。 因此,如果我们将代码更改为:

 string a = new string('x', 1); string b = new string('x', 1); Console.WriteLine(a.Equals((object) b)); object c = a; object d = b; Console.WriteLine(c.Equals(d)); 

…然后编译代码中的两个方法调用将只是object.Equals(object) ,但由于多态性,它们仍然都会打印True:将使用String的实现。

以下是对重载方法的调用:

 string a = new string('x', 1); string b = new string('x', 1); Console.WriteLine(a.Equals(b)); // Calls string.Equals(string) 

引用Equals的文档:

Equals的默认实现支持引用类型的引用相等,以及值类型的按位相等。 引用相等意味着被比较的对象引用引用相同的对象。 按位相等意味着被比较的对象具有相同的二进制表示。

和==运算符 :

对于预定义的值类型,如果操作数的值相等,则相等运算符(==)返回true,否则返回false。 对于除string之外的引用类型,如果其两个操作数引用同一对象,则==返回true。 对于字符串类型,==比较字符串的值。

现在回到你的问题:为什么s1 == s2返回true? 字符串是.NET中的特殊动物。 它们表示不可变引用类型。 他们在.NET中实习。 这意味着如果您有2个具有相同值的字符串常量,它们将在运行时引用相同的对象实例。

从文档中引用:

公共语言运行库通过维护一个名为intern pool的表来保存字符串存储,该表包含对程序中以编程方式声明或创建的每个唯一文字字符串的单个引用。 因此,具有特定值的文字字符串实例仅在系统中存在一次。

你的想法似乎是Java风格。 在java中, ==运算符不能自定义,因此对于引用类型,它始终表示引用相等,而它表示基本类型的值相等。 另一方面, Equals用于检查引用类型中的值相等性。

但是,C#的情况有所不同。 Equals==都可以有自定义实现。 区别在于Equals是一个虚拟(实例)方法,而operator==是一个静态方法。 除此之外,他们可以以完全相同的方式行事。

默认情况下, Equals==检查引用类型的引用相等性,以及值类型的值相等性。 但是,对于string ,两者都是自定义的以检查值的相等性。