首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >IEquatable<T>.Equals来自MSDN

IEquatable<T>.Equals来自MSDN
EN

Stack Overflow用户
提问于 2016-01-19 03:17:15
回答 1查看 71关注 0票数 0

我在看MSDN上的IEquatable.Equals。具体来说,这两个部分的部分等于操作符:

代码语言:javascript
复制
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);
}

我一直在纠结的是:

代码语言:javascript
复制
if (((object)person1) == null || ((object)person2) == null)
   return Object.Equals(person1, person2);
  1. 为什么要在检查对象是否为空之前将其转换为对象?它是否还有更多的内容,或者它是否同样容易地被表达为if ( person1 == null || person2 == null )
  2. 为什么打电话给Object.Equals?当然,如果其中一个项为空,那么它就是false

在我看来,

代码语言:javascript
复制
if (((object)person1) == null || ((object)person2) == null)
   return Object.Equals(person1, person2);

只是一种复杂的写作方式:

代码语言:javascript
复制
if ( person1 == null || person2 == null )
   return false;

还是我漏掉了什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-01-19 03:43:58

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

您处于==的重载状态,因此如果不进行转换,就会调用该重载,并且会出现带有堆栈溢出的无限递归(或者更糟的是,如果它成功地优化了尾调用,则会有一个无限循环)。你需要确保你把object==打给你而不是你自己。

为什么打电话给Object.Equals?当然,如果其中一个项是空的,那么它就是false

如果它们都为,则为空,则为真。

因此,这是有道理的。不过我不推荐。仅仅完成空检查本身就更简单了:

代码语言:javascript
复制
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.

我们可以在这里做几种不同的模式。我们也可以:

代码语言:javascript
复制
if ((object)person1 == null && (object)person2 == null) return true;
if ((object)person1 == null || (object)person2 == null) return false;
// Follow with rest of logic.

到目前为止,仅仅是一个额外的比较,就有很多不同之处。仍然检查一个引用是否与另一个引用相同(包括检查它是否为空)是很便宜的。让我们把树枝去掉,这样:

代码语言:javascript
复制
if ((object)person1 == null & (object)person2 == null) return true;
if ((object)person1 == null | (object)person2 == null) return false;
// Follow with rest of logic.

在每一行中,潜在不必要的检查的额外成本很可能低于是否执行分支的成本,因此这是一次胜利。

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

代码语言:javascript
复制
if ((object)person1 == (object)person2) return true;
if ((object)person1 == null | (object)person2 == null) return false;
// Follow with rest of logic.

现在,除了处理它们都为null的情况之外,我还处理了它们都是同一个对象的情况。由于它具有相同的引用-标识检查,所以这几乎不会增加方法的成本,但是如果我们必须检查很多东西以确保两项相等(考虑检查两个非常大的字符串,并且在检查每个字符或排序单位后才知道它们是相同的),那么它就给了我们一个快速的true,它可能是非常慢的true

现在,让我们考虑一下,Equals()是我们拥有大部分逻辑的地方。如果我们应用上述方法,我们可以在以下两种方法之间进行选择:

代码语言:javascript
复制
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);
}

代码语言:javascript
复制
public static bool operator == (Person person1, Person person2)
{
  if ((object)person1 == (object)person2)
    return true;
  return ((object)person1 != null  && person1.Equals(person2);
}

后者取决于这样一个事实,即person1.Equals(person2)将检查person2是否为空。当person2为null时,前者(因为它避免了分支)可能是一次轻微的胜利,而后者则可能是一次轻微的胜利,而且更加简洁。我一般会选后者。

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

顺便说一句,他们对object.Equals()建议的覆盖,我完全不建议:

代码语言:javascript
复制
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);
}

如果您删除了第一个空检查,那么第二个检查仍然会捕获该情况。

如果您删除了第二个null检查,那么对Equals()的调用(接受Person的重载调用)将捕获它。

因此,它应该是:

代码语言:javascript
复制
public override bool Equals(object obj)
{
  return Equals(obj as Person);
}

该模式将用作实现Equals(object)的任何类的IEquatable<T>覆盖(在某些情况下,您可能希望将对象视为不同类型的对象之一,但即使是这样做,这些对象也是罕见的,而且常常是错误的,因此应该被认为是非常特殊的情况)。对于任何您可以使用的结构:

代码语言:javascript
复制
public override bool Equals(object obj)
{
  return obj is TheStructType && Equals((TheStructType)obj);
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34867958

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档