重载运算符==与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等于重载运算符等于