C# IEquatable<;T>;。来自MSDN的等于

C# IEquatable<;T>;。来自MSDN的等于,c#,iequatable,C#,Iequatable,我在看。特别是两个Equals运算符的部分: 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

我在看。特别是两个Equals运算符的部分:

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)
      return Object.Equals(person1, person2);

   return person1.Equals(person2);
}
我正在努力解决的问题是:

if (((object)person1) == null || ((object)person2) == null)
   return Object.Equals(person1, person2);
  • 为什么在检查对象是否为空之前将其强制转换为对象?如果(person1==null | | person2==null),它还有更多的含义吗?或者它可以同样容易地表达出来吗
  • 为什么要调用Object.Equals?如果其中一项为空,那么肯定是
    false
  • 在我看来

    if (((object)person1) == null || ((object)person2) == null)
       return Object.Equals(person1, person2);
    
    这只是一种复杂的写作方式:

    if ( person1 == null || person2 == null )
       return false;
    
    还是我遗漏了什么

    为什么在检查对象是否为空之前将其强制转换为对象

    您处于一个
    =
    的重载中,因此如果您没有强制转换,您会调用该重载,并且会出现带有堆栈溢出的无限递归(或者更糟糕的是,如果它成功地优化了尾部调用,则会出现无限循环)。您需要确保您调用的是对象的
    ==
    ,而不是您自己的

    为什么要调用Object.Equals?如果其中一项为空,那么肯定是
    false

    如果它们为空,则这是真的

    因此,这是有道理的。不过我不推荐。只需完整地执行空检查就更简单了:

    if ((object)person1 == null)
      return (object)person2 == null;
    if ((object)person2 == null)
      return false; // we already know person1 isn't null
    // Follow with rest of logic.
    
    这里我们可以做一些不同的模式。我们也可以这样做:

    if ((object)person1 == null && (object)person2 == null) return true;
    if ((object)person1 == null || (object)person2 == null) return false;
    // Follow with rest of logic.
    
    到目前为止,仅仅通过一个额外的比较,就可以得出很多结论。仍然检查一个引用是否与另一个引用相同(包括检查它是否为null)是很便宜的。让我们去掉树枝,这样:

    if ((object)person1 == null & (object)person2 == null) return true;
    if ((object)person1 == null | (object)person2 == null) return false;
    // Follow with rest of logic.
    
    每行中潜在的不必要检查的额外成本可能低于分支机构是否进行检查的成本,因此这是一个胜利

    但是现在考虑第一行是检查它们是否都是空的。实际上,这只是它们都是同一实例的一个子集。让我们检查一下:

    if ((object)person1 == (object)person2) return true;
    if ((object)person1 == null | (object)person2 == null) return false;
    // Follow with rest of logic.
    
    现在,除了处理它们都为null的情况外,我还处理它们都是相同对象的情况。由于这两种方法都是相同的引用标识检查,因此这几乎不会增加方法的成本,但是如果我们必须检查很多东西以确保两个项相等(请考虑检查两个非常大的字符串,并在检查每个字符或排序单元后才知道它们是相同的)它为我们提供了一个快速的
    true
    ,而这可能是一个非常缓慢的
    true

    现在让我们考虑<代码>均衡器()>代码>,我们将得到大部分逻辑。如果我们采用上述方法,我们可以选择:

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

    后者取决于
    person1.Equals(person2)
    将检查
    person2
    是否为空。前者(因为它避免了分支)在
    person2
    为空时可能是一个小胜利,但后者在其他情况下可能是一个小胜利,并且更简洁。我一般会选择后者

    因此,在您引用的示例中使用
    object.Equals()
    是有效的,但这不是我推荐的方法


    顺便提一下,他们建议对
    object.Equals()

    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);
    }
    
    如果删除第一个空检查,那么第二个空检查仍然会捕获该情况

    如果取消第二个空检查,那么对
    Equals()
    (重载的一个,需要一个
    Person
    )的调用将捕获它

    因此,它应该是:

    public override bool Equals(object obj)
    {
      return Equals(obj as Person);
    }
    

    此模式将用作<代码> > IEQuabtI/<代码>的任何类的<代码>(对象)< /代码>重写(可能会有这样的情况,即你想把这个对象等同于一个不同类型的对象,但那些是罕见的,即使在完成时也是错误的,因此应该被认为是非常特殊的情况)。对于您可以使用的任何结构:

    public override bool Equals(object obj)
    {
      return obj is TheStructType && Equals((TheStructType)obj);
    }
    
    为什么在检查对象是否为空之前将其强制转换为对象

    您处于一个
    =
    的重载中,因此如果您没有强制转换,您会调用该重载,并且会出现带有堆栈溢出的无限递归(或者更糟糕的是,如果它成功地优化了尾部调用,则会出现无限循环)。您需要确保您调用的是对象的
    ==
    ,而不是您自己的

    为什么要调用Object.Equals?如果其中一项为空,那么肯定是
    false

    如果它们为空,则这是真的

    因此,这是有道理的。不过我不推荐。只需完整地执行空检查就更简单了:

    if ((object)person1 == null)
      return (object)person2 == null;
    if ((object)person2 == null)
      return false; // we already know person1 isn't null
    // Follow with rest of logic.
    
    这里我们可以做一些不同的模式。我们也可以这样做:

    if ((object)person1 == null && (object)person2 == null) return true;
    if ((object)person1 == null || (object)person2 == null) return false;
    // Follow with rest of logic.
    
    到目前为止,仅仅通过一个额外的比较,就可以得出很多结论。仍然检查一个引用是否与另一个引用相同(包括检查它是否为null)是很便宜的。让我们去掉树枝,这样:

    if ((object)person1 == null & (object)person2 == null) return true;
    if ((object)person1 == null | (object)person2 == null) return false;
    // Follow with rest of logic.
    
    每行中潜在的不必要检查的额外成本可能低于分支机构是否进行检查的成本,因此这是一个胜利

    但是现在考虑第一行是检查它们是否都是空的。实际上,这只是它们都是同一实例的一个子集。让我们检查一下:

    if ((object)person1 == (object)person2) return true;
    if ((object)person1 == null | (object)person2 == null) return false;
    // Follow with rest of logic.
    
    现在,除了处理它们都为null的情况外,我还处理它们都是相同对象的情况。由于这两种方法都是相同的引用标识检查,因此这几乎不会增加方法的成本,但是如果我们必须检查很多东西以确保两个项相等(请考虑检查两个非常大的字符串,并在检查每个字符或排序单元后才知道它们是相同的)它为我们提供了一个快速的
    true
    ,而这可能是一个非常缓慢的
    true

    现在让我们考虑<代码>均衡器()>代码>,我们将得到大部分逻辑。如果我们采用上述方法,我们可以选择:

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

    后者取决于
    person1.Equals(person2)
    将检查
    person2
    是否为空。当
    person2
    为空时,前者(因为它避免了分支)可能是一个小胜利,但后者可能是b