重载运算符==与Equals()
我正在开发一个C#项目,到目前为止,我已经使用了不可变的对象和工厂来确保types为Foo
对象始终可以与==
进行比较。
Foo
对象一旦创build就无法更改,工厂总是为给定的参数集返回相同的对象。 这很好,而且在整个代码库中,我们假设==
总是用于检查相等性。
现在我需要添加一些function,引入一个边缘情况,这不会总是工作。 最简单的做法是重载operator ==
这个types,这样项目中的其他代码都不需要改变。 但是,这使我感到代码味道:重载operator ==
而不是Equals
看起来很奇怪,我习惯于==
检查引用相等的约定,而Equals
检查对象相等(或任何术语)。
这是一个合理的关注,或者我应该继续并重载运operator ==
?
我相信标准是对于大多数types,.Equals检查对象的相似性,而operator ==
检查引用的相等性。
我相信最好的做法是对于不可变的types,operator ==
应该检查相似性,以及.Equals
。 如果你想知道他们是否真的是同一个对象,使用.ReferenceEquals
。 请参阅C# String
类的示例。
重载 ==
和重载 Equals之间有很大的区别。
当你有expression
if (x == y) {
将用于比较variablesx和y的方法在编译时决定。 这是运算符重载。 声明x和y时使用的types用于定义使用哪种方法比较它们。 x和y中的实际types(即子类或接口实现)是不相关的。 考虑以下几点。
object x = "hello"; object y = 'h' + "ello"; // ensure it's a different reference if (x == y) { // evaluates to FALSE
和以下
string x = "hello"; string y = 'h' + "ello"; // ensure it's a different reference if (x == y) { // evaluates to TRUE
这表明用于声明variablesx和y的types用于确定哪个方法用于评估==。
通过比较,Equals是基于variablesx中的实际types在运行时确定的。 Equals是Object上的一个虚拟方法,其他types可以重写。 因此下面的两个例子都评价为真。
object x = "hello"; object y = 'h' + "ello"; // ensure it's a different reference if (x.Equals(y)) { // evaluates to TRUE
和以下
string x = "hello"; string y = 'h' + "ello"; // ensure it's a different reference if (x.Equals(y)) { // also evaluates to TRUE
它绝对有味道。 当重载==
你应该确保Equals()
和GetHashCode()
也是一致的。 请参阅MSDN指南 。
唯一的原因就是你把你的types描述为不可变的。
对于不可变的types,我不认为有==
重载支持值相等的任何错误。 我不认为我会重写==
而不重写Equals
具有相同的语义。 如果你重写==
并且由于某种原因需要检查引用的相等性,你可以使用Object.ReferenceEquals(a,b)
。
有关一些有用的指导,请参阅Microsoft文章
示例显示如何根据MSFT准则 (如下)执行此操作。 请注意,在重写Equals时,您还需要重写GetHashCode()。 希望这可以帮助人们。
public class Person { public Guid Id { get; private set; } public Person(Guid id) { Id = id; } public Person() { Id = System.Guid.NewGuid(); } public static bool operator ==(Person p1, Person p2) { bool rc; if (System.Object.ReferenceEquals(p1, p2)) { rc = true; } else if (((object)p1 == null) || ((object)p2 == null)) { rc = false; } else { rc = (p1.Id.CompareTo(p2.Id) == 0); } return rc; } public static bool operator !=(Person p1, Person p2) { return !(p1 == p2); } public override bool Equals(object obj) { bool rc = false; if (obj is Person) { Person p2 = obj as Person; rc = (this == p2); } return rc; } public override int GetHashCode() { return Id.GetHashCode(); } }
根据微软自己的最佳实践,Equals方法和equals(==)重载的结果应该是相同的。
CA2224:Override等于重载运算符等于