==或者.Equals()
为什么要一个使用另一个?
解决方案
==是身份测试。如果两个要测试的对象实际上是同一个对象,它将返回true。 Equals()
执行相等性测试,如果两个对象认为自己相等,则返回true。
身份测试速度更快,因此在不需要更昂贵的相等性测试时可以使用它。例如,与null
或者空字符串进行比较。
可以重载这两个参数中的任何一个以提供不同的行为,例如对Equals()进行身份测试,但是为了任何人都阅读代码,请不要这样做。
下面指出:一些类型,例如String或者DateTime,为==运算符提供了重载,从而赋予了其相等的语义。因此,确切的行为将取决于我们正在比较的对象的类型。
也可以看看:
- http://blogs.msdn.com/csharpfaq/archive/2004/03/29/102224.aspx
如果要表达比较的对象的内容应该相等,请使用equals。对原始值使用==,或者如果要检查比较的对象是否是一个相同的对象,请使用==。对于对象==检查对象的地址指针是否相同。
==通常表示"身份"等于"对象a实际上是与对象b在内存中完全相同的对象"。
equals()表示对象在逻辑上相等(例如,从业务角度而言)。因此,如果我们要比较用户定义的类的实例,则通常需要使用和定义equals()才能使Hashtable之类的东西正常工作。
如果我们有一个带有属性"名称"和"地址"的著名的Person类,并且我们想将此Person用作包含有关它们的更多信息的Hashtable的键,则需要实现equals()(和hash),以便我们可以创建一个Person的实例,并将其用作哈希表中的键以获取信息。
单独使用==,新实例将不一样。
根据MSDN:
在C#中,有两种不同的相等类型:引用相等(也称为标识)和值相等。值相等是人们普遍理解的意义,它表示两个对象包含相同的值。例如,值为2的两个整数具有相等的值。引用相等意味着没有两个要比较的对象。而是有两个对象引用,并且它们两个都引用同一个对象。
...
默认情况下,运算符==通过确定两个引用是否指示同一对象来测试引用是否相等。
该示例是因为类DateTime实现了IEquatable接口,该接口实现了"用于确定实例是否相等的特定于类型的方法"。根据MSDN。
要考虑的另一件事:如果我们从另一种语言访问该对象,则==运算符可能不可调用或者可能具有不同的含义。通常,最好有一个可以通过名称调用的替代方法。
其他人几乎都覆盖了我们,但我还有一个建议。时不时地,我们会发誓对自己(以及他所爱的人)的生活发誓,"。等于"是更有效率/更好/最佳实践或者其他教条主义的路线。我不能说效率(好吧,在某些情况下可以),但是我可以说一个大问题,这个问题会冒出来:.Equals
需要一个对象存在。 (听起来很愚蠢,但是却把人们拒之门外。)
我们不能执行以下操作:
StringBuilder sb = null; if (sb.Equals(null)) { // whatever }
对我(也许对大多数人而言)似乎很明显,我们将得到一个NullReferenceException
。然而,.equals的支持者却忘了那个小事实。当看到NullRefs开始弹出时,有些甚至被"抛出"(抱歉,无法抗拒)。
(在DailyWTF发布之前的几年,我确实与要求所有均等性检查为.Equals
而不是==
的人一起工作。即使证明他的不准确性也没有帮助。其他规则,这样就不会从方法或者属性返回的引用永远为null,并且最终会得出结论。)
@约翰·米利金(John Millikin):
Pointed out below: some value types like DateTime provide overloads for the == operator >that give it equality semantics. So the exact behavior will depend on the types of the >objects you are comparing.
详细说明:
DateTime被实现为一个结构。所有结构都是System.ValueType的子级。
由于System.ValueType的子代驻留在堆栈上,因此没有指向堆的引用指针,因此无法进行引用检查,因此必须仅按值比较对象。
System.ValueType覆盖.Equals()和==以使用基于反射的相等性检查,它使用反射来比较每个字段的值。
因为反射有点慢,所以如果实现自己的结构,则覆盖.Equals()并添加自己的值检查代码非常重要,因为这样做会更快。不要只调用base.Equals();
我已经看到了Object.ReferenceEquals()用于想要知道两个引用是否引用同一个对象的情况