我正在看IEquatable.Equals on MSDN。特别是两个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);
if ( person1 == null || person2 == null )
?false
?我看待它的方式,
if (((object)person1) == null || ((object)person2) == null)
return Object.Equals(person1, person2);
只是一种令人费解的写作方式:
if ( person1 == null || person2 == null )
return false;
或者我错过了什么?
答案 0 :(得分:2)
为什么在检查是否为空之前将转换为对象?
你处于==
的重载状态,所以如果你没有强制转换你会调用那个重载,并且堆栈溢出会有无限递归(或者更糟,如果它管理了被尾部调用优化,无限循环)。您需要确保拨打object
的{{1}}而不是您自己的电话。
为什么调用Object.Equals?当然,如果其中一个项目为null,那么它是
==
?
如果它们都为空,那就不是,那就是真的。
因此这是有道理的。我不推荐它。只做整个本身的空检查更简单:
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.
每一行中可能不必要的检查的额外费用可能低于分支机构是否要这样做的费用,所以这是一个胜利。
但现在考虑第一行是检查它们是否都为空。真的,这只是他们两个案例的一个子集是同一个实例。我们只需检查一下:
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 == (object)person2) return true;
if ((object)person1 == null | (object)person2 == null) return false;
// Follow with rest of logic.
,这可能是一个非常慢的true
。
现在让我们考虑true
是我们将拥有大部分逻辑的地方。如果我们应用上述内容,我们可以选择:
Equals()
和
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);
}
后者取决于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
是有效的,但这不是我建议的方法。
顺便说一句,他们建议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);
}
的任何类的Equals(object)
覆盖(可能存在您想要将对象视为不同类型的对象的情况,但这些很少见且经常即使完成它们也是错误的,因此应该被认为是一个非常专业的案例)。对于您可以使用的任何结构:
IEquatable<T>