C# 中 == 运算符和 Equals() 方法的区别?
Posted
技术标签:
【中文标题】C# 中 == 运算符和 Equals() 方法的区别?【英文标题】:Difference between == operator and Equals() method in C#? 【发布时间】:2012-03-20 17:27:40 【问题描述】:==
和Equals()
有什么区别?我知道==
用于比较运算符,Equals()
方法用于比较字符串的内容。所以我尝试了
// 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");
我收到无法将字符串转换为字符的编译时错误
【问题讨论】:
Equals()方法不只是用来比较一个字符串的内容,它可以用来比较any两个对象。 C# 中的string
类型碰巧 包含Equals()
的覆盖方法,该方法将比较它们的值(这一事实在许多文章中解释得很差,这些文章表明Equals()
用于字符串仅供比较)。
【参考方案1】:
有几件事正在发生。首先,在这个例子中:
string s1 = "a";
string s2 = "a";
Console.WriteLine(s1 == s2);
您声称:
两者都是不同的对象引用。
由于字符串实习,这不是真的。 s1
和 s2
是对同一个对象的引用。 C# 规范保证 - 从 C# 4 规范的第 2.4.4.5 节:
当根据字符串相等运算符(第 7.10.7 节)等效的两个或多个字符串文字出现在同一程序中时,这些字符串文字引用相同的字符串实例。
因此在这种特殊情况下,即使您打印了object.ReferenceEquals(s1, s2)
,或者如果您使用与==
的真实参考身份比较,您仍然会得到“真实”:
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
中的实现.
overloaded 方法的调用如下所示:
string a = new string('x', 1);
string b = new string('x', 1);
Console.WriteLine(a.Equals(b)); // Calls string.Equals(string)
【讨论】:
两个问题:为什么要把d
转换成object
,因为它已经是一个对象了?另外,在a Equals b
部分,我会同时调用对象覆盖和字符串重载,因此更清楚区别是什么。
@doekman: 1) 是的,在这种情况下我不需要演员表。 2) 不确定你的意思。
我的意思是:见最后一个答案。我没有直接得到你关于重载/覆盖的解释......【参考方案2】:
引用Equals的文档:
Equals 的默认实现支持引用相等 引用类型和值类型的按位相等。参考 相等意味着被比较的对象引用引用 同一个对象。按位相等意味着被比较的对象有 相同的二进制表示。
还有== operator:
对于预定义的值类型,相等运算符 (==) 在以下情况下返回 true 其操作数的值相等,否则为假。以供参考 字符串以外的类型,如果两个操作数引用 ==,则返回 true 同一个对象。对于字符串类型,== 比较 字符串。
现在回到你的问题:为什么s1 == s2
返回真?字符串是 .NET 中的特殊野兽。它们代表不可变的引用类型。他们在 .NET 中实习。这意味着如果您有 2 个具有相同值的字符串常量,它们将在运行时引用相同的对象实例。
引用自documentation:
公共语言运行时通过维护一个 表,称为实习生池,其中包含对 以编程方式声明或创建的每个唯一文字字符串 你的程序。因此,文本字符串的实例具有 特定值在系统中只存在一次。
【讨论】:
不是单独因为实习。实习就是为什么即使它们被声明为object
类型也会起作用。但是,由于运算符重载,只要涉及的编译时类型都是字符串,即使对具有相同内容的不同字符串对象的引用也可以工作。您引用的文档具有误导性,因为它表明存在一些特殊处理 仅针对字符串 - 没有,只是字符串是 a 引用类型,它重载了 = = 运算符。
另请注意,实习是一种语言细节——.NET 提供了机制,但很可能有一种语言 Dumb#,它在各方面都与 C# 相同,除了没有字符串常量实习。【参考方案3】:
你的想法似乎是 Java 风格的。在java中,==
操作符不能自定义,所以对于引用类型,它总是表示引用相等,而对于原始类型它表示值相等。另一方面,Equals
用于检查引用类型中的值相等性。
不过,C# 中的情况有所不同。 Equals
和 ==
都可以有自定义实现。区别在于Equals
是虚拟(实例)方法,而operator==
是静态方法。除此之外,它们的行为方式完全相同。
默认情况下,Equals
和 ==
都检查引用类型的引用相等性和值类型的值相等性。但是,对于string
,两者都被定制为检查值是否相等。
【讨论】:
以上是关于C# 中 == 运算符和 Equals() 方法的区别?的主要内容,如果未能解决你的问题,请参考以下文章