MSDN代码示例:为什么它在调用静态Object.Equals之前检查null

本文关键字:Equals Object 静态 null 检查 调用 代码 为什么 MSDN | 更新日期: 2023-09-27 18:21:59

在Microsoft MSDN Library关于IEquatable<T>.Equals方法的文章中(http://msdn.microsoft.com/en-us/library/ms131190.aspx)举例说明了如何重写Equals和Equality运算符。它看起来像这样:

public class Person : IEquatable<Person>
{
   private string uniqueSsn;
   private string lName;
   public bool Equals(Person other) 
   {
      if (other == null) 
         return false;
      if (this.uniqueSsn == other.SSN)
         return true;
      else 
         return false;
   }
   public override bool Equals(Object obj)
   {
      if (obj == null) 
         return false;
      Person personObj = obj as Person;
      if (personObj == null)
         return false;
      else    
         return Equals(personObj);   
   }   
   public static bool operator == (Person person1, Person person2)
   {
      if ((object)person1 == null || ((object)person2) == null) // Here !!!
         return Object.Equals(person1, person2);
      return person1.Equals(person2);
   }
   ...
}

我的注意力被吸引到了这条线上:if ((object)person1 == null || ((object)person2) == null) return Object.Equals(person1, person2);

据我所知,静态Object.Equals会自动为其参数检查null。为什么在调用它之前要再次检查null?有这样做的指导方针吗?

我会像这样简单地实现它:

   public static bool operator == (Person person1, Person person2)
   {
         return Object.Equals(person1, person2);
   }

或者这个:

   public static bool operator == (Person person1, Person person2)
   {
      if ((object)person1 == null)
         return ((object)person2 == null)
      return person1.Equals(person2);
   }

基于同一文档中的这句话:"如果你覆盖了Object.Equals(Object),那么在对类上static Equals(System.Object, System.Object)方法的调用中也会调用你的覆盖实现"

更新:

我在public bool Equals(Person other)中发现了一个可能的错误,它写道:other == null,其中==过载!尽管结果是正确的,但还有一个额外的间接级别。我认为应该是(object)other == null

MSDN代码示例:为什么它在调用静态Object.Equals之前检查null

您的方法最终会调用虚拟Equals(Object)方法,因为Object.Equals就是这样做的。这里给出的方法只在至少一个值为null时使用Object.Equals,以便在它们都为null和false的情况下返回true,否则-该路径将永远不会回调到Equals实现中。

如果两个值都不是null,MSDN方法将直接对bool Equals(Person)进行非虚拟调用,这不仅避免了虚拟方法间接调用,还避免了另一种类型检查,当我们已经知道如果引用是非null,则它们都是Person引用时,这种检查是多余的。

我认为这个例子是不幸的,因为它混合了使用字段和属性,请注意——我肯定会这样写:

if (this.uniqueSsn == other.SSN)
   return true;
else 
   return false;

正如:

return this.uniqueSsn == other.SSN;

或者更明显的是:

return this.uniqueSsn == other.uniqueSsn;