覆盖==运算符。 如何比较为空?
可能重复:
如何在没有无限recursion的情况下检查'=='运算符超载的空值?
这可能是一个简单的答案,但它似乎逃避我。 这是一个简单的例子:
public class Person { public string SocialSecurityNumber; public string FirstName; public string LastName; }
假设对于这个特定的应用程序来说,如果社会安全号码匹配,并且两个名称都匹配,那么我们指的是同一个“人”是有效的。
public override bool Equals(object Obj) { Person other = (Person)Obj; return (this.SocialSecurityNumber == other.SocialSecurityNumber && this.FirstName == other.FirstName && this.LastName == other.LastName); }
为了保持一致,我们重写==和!=运算符,对于团队中不使用.Equals
方法的开发人员。
public static bool operator !=(Person person1, Person person2) { return ! person1.Equals(person2); } public static bool operator ==(Person person1, Person person2) { return person1.Equals(person2); }
精致而华丽,对吗?
但是,当Person对象为null
时会发生什么?
你不能写:
if (person == null) { //fail! }
由于这将导致==运算符覆盖运行,并且代码将失败:
person.Equals()
方法调用,因为你不能在空实例上调用一个方法。
另一方面,你不能明确地检查==覆盖内的这个条件,因为它会导致无限recursion(和堆栈溢出[点击])
public static bool operator ==(Person person1, Person person2) { if (person1 == null) { //any code here never gets executed! We first die a slow painful death. } return person1.Equals(person2); }
那么,如何重写==和!=运算符来实现值相等,并仍占空对象呢?
我希望答案不是很简单。 🙂
使用object.ReferenceEquals(person1, null)
代替==
运算符:
public static bool operator ==(Person person1, Person person2) { if (object.ReferenceEquals(person1, null)) { return object.ReferenceEquals(person2, null); } return person1.Equals(person2); }
你可以总是覆盖和放
(Object)(person1)==null
我想这会工作,但不知道。
我一直这样做(对于==和!=运算符),我重复使用这个代码为我创build的每个对象:
public static bool operator ==(Person lhs, Person rhs) { // If left hand side is null... if (System.Object.ReferenceEquals(lhs, null)) { // ...and right hand side is null... if (System.Object.ReferenceEquals(rhs, null)) { //...both are null and are Equal. return true; } // ...right hand side is not null, therefore not Equal. return false; } // Return true if the fields match: return lhs.Equals(rhs); }
“!=”然后像这样:
public static bool operator !=(Person lhs, Person rhs) { return !(lhs == rhs); }
编辑
我修改了==
运算符函数以匹配Microsoftbuild议的实现。
将Person
实例转换为object
:
public static bool operator ==(Person person1, Person person2) { if ((object)person1 == (object)person2) return true; if ((object)person1 == null) return false; if ((object)person2 == null) return false; return person1.Equals(person2); }
一致地重载这些操作符是非常困难的。 我对相关问题的回答可以作为模板。
基本上,你首先需要做一个引用( object.ReferenceEquals
)testing,看看对象是否为null
。 然后你打电话给Equals
。
将Person转换为Object,然后执行比较:
object o1 = (object)person1; object o2 = (object)person2; if(o1==o2) //compare instances. return true; if (o1 == null || o2 == null) //compare to null. return false; //continue with Person logic.
最后的(假设)例程如下。 这与@ cdhowie第一个被接受的反应非常相似。
public static bool operator ==(Person person1, Person person2) { if (Person.ReferenceEquals(person1, person2)) return true; if (Person.ReferenceEquals(person1, null)) return false; //* return person1.Equals(person2); }
感谢您的好评!
// * – .Equals()
对person2执行null检查
cdhowie是使用ReferenceEquals
的钱,但值得注意的是,如果有人将null
直接传递给Equals
,你仍然可以得到一个exception。 另外,如果你打算重写Equals
那么实现IEquatable<T>
几乎总是值得的,所以我会改为。
public class Person : IEquatable<Person> { /* more stuff elided */ public bool Equals(Person other) { return !ReferenceEquals(other, null) && SocialSecurityNumber == other.SocialSecurityNumber && FirstName == other.FirstName && LastName == other.LastName; } public override bool Equals(object obj) { return Equals(obj as Person); } public static bool operator !=(Person person1, Person person2) { return !(person1 == person2); } public static bool operator ==(Person person1, Person person2) { return ReferenceEquals(person1, person2) || (!ReferenceEquals(person1, null) && person1.Equals(person2)); } }
当然,你不应该覆盖Equals
,也不应该重写GetHashCode()
public override int GetHashCode() { //I'm going to assume that different //people with the same SocialSecurityNumber are extremely rare, //as optimise by hashing on that alone. If this isn't the case, change this return SocialSecurityNumber.GetHashCode(); }
同样值得注意的是,身份需要平等(也就是说,对于任何有效的“平等”概念而言,某事总是等于自身)。 由于相等性testing可能是昂贵的,并且出现在循环中,并且由于在真实的代码中比较某些东西往往是相当普遍的(特别是如果对象在几个地方传递),所以值得添加一个快捷方式:
public bool Equals(Person other) { return !ReferenceEquals(other, null) && ReferenceEquals(this, other) || ( SocialSecurityNumber == other.SocialSecurityNumber && FirstName == other.FirstName && LastName == other.LastName ); }
ReferenceEquals(this, other)
快捷方式有多less可以根据类的性质而有很大的不同,但是在做或不做的时候值得一看,所以我把这个技巧包含在这里。
比任何这些方法更容易使用
public static bool operator ==(Person person1, Person person2) { EqualityComparer<Person>.Default.Equals(person1, person2) }
这与其他人提出的方法具有相同的空等式语义,但这是框架的问题,要弄清楚细节:)