简体   繁体   English

quaqua <T> 从MSDN等于

[英]IEquatable<T>.Equals from MSDN

I'm looking at IEquatable.Equals on MSDN . 我正在看MSDN上的IEquatable.Equals Specifically the section for the two Equals operators: 特别是两个等于运算符的部分:

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);
}

The line I'm struggling with is: 我正在努力的那条线是:

if (((object)person1) == null || ((object)person2) == null)
   return Object.Equals(person1, person2);
  1. Why the cast to object before checking if it's null? 为什么在检查对象是否为null之前将其强制转换为对象? Is there more to it or could it just as easily been expressed if ( person1 == null || person2 == null ) ? if ( person1 == null || person2 == null )可以简单地表达吗?
  2. Why the call to Object.Equals? 为什么调用Object.Equals? Surely if one of the items is null then it's false ? 当然,如果其中一项为null,那么它为false吗?

The way I see it, 我的看法

if (((object)person1) == null || ((object)person2) == null)
   return Object.Equals(person1, person2);

is just a convoluted way of writing: 只是一种令人费解的写作方式:

if ( person1 == null || person2 == null )
   return false;

or am I missing something? 还是我错过了什么?

Why the cast to object before checking if it's null? 为什么在检查对象是否为null之前将其强制转换为对象?

You're in an overload of == so you'd call back into that overload if you didn't cast, and there'd be infinite recursion with a stack-overflow (or worse, if it managed to be tail-call optimised, an infinite loop). 您处于==的重载状态,因此如果不进行强制转换,则会调用该重载,并且堆栈溢出会无限循环(或更糟糕的是,如果设法对尾部调用进行了优化) ,无限循环)。 You need to make sure you call object 's == not your own. 您需要确保调用object==而不是您自己的。

Why the call to Object.Equals? 为什么调用Object.Equals? Surely if one of the items is null then it's false ? 当然,如果其中一项为null,那么它为false吗?

Not if they're both null, then it's true. 如果它们都为空,则不然,这是事实。

As such it makes sense. 因此,这是有道理的。 I don't recommend it though. 我不推荐它。 It's simpler just to do that null check in its entirety itself: 只对整个null本身进行null检查就更简单了:

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.

There are a few different patterns we can do here. 我们可以在此处执行几种不同的模式。 We could just as well do: 我们也可以这样做:

if ((object)person1 == null && (object)person2 == null) return true;
if ((object)person1 == null || (object)person2 == null) return false;
// Follow with rest of logic.

So far, much of a muchness with just one extra comparison. 到目前为止,仅需进行一个额外的比较就可以实现很多功能。 Still checking if a reference is the same as another (including checking if it's null) is cheap. 仍然检查引用是否与另一个引用相同(包括检查它是否为空)很便宜。 Let's get rid of branches so: 让我们摆脱分支,以便:

if ((object)person1 == null & (object)person2 == null) return true;
if ((object)person1 == null | (object)person2 == null) return false;
// Follow with rest of logic.

The extra cost of the potentially unnecessary check in each line is likely less than the cost of the branch on whether or not to do it, so this is a win. 每行中潜在不必要检查的额外费用可能会比分支机构是否执行检查的费用要少,因此这是一个胜利。

But now consider that the first line is checking if they're both null. 但是现在考虑第一行正在检查它们是否都为空。 Really that's just a subset of the cases of them both being the same instance. 确实,这只是它们都是同一实例的情况的一部分。 Let's just check for that instead: 让我们检查一下:

if ((object)person1 == (object)person2) return true;
if ((object)person1 == null | (object)person2 == null) return false;
// Follow with rest of logic.

Now as well as handling the case where they are both null, I handle the case where they are both the same object. 现在,除了处理它们均为null的情况外,我还将处理它们都是同一对象的情况。 Since its the same reference-identity check either way this pretty much adds no cost to the method, but if we have to check lots of things to be sure two items are equal (consider checking two very large strings and only knowing they're the same after checking each character or collation unit) it gives us a fast true on what could have been a very slow true . 由于以相同的方式进行相同的引用身份检查,因此这几乎不会增加方法的成本,但是如果我们必须检查很多事情以确保两个项目相等(考虑检查两个非常大的字符串,并且仅知道它们是检查每个字符或归类单元后同),它为我们提供了一个快速的true上什么可能是一个非常缓慢的true

Now let's consider that Equals() is where we'll have most of this logic. 现在让我们考虑使用Equals()来处理大部分逻辑。 If we apply the above we've a choice between: 如果我们采用上述方法,我们可以选择:

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);
}

And

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

The latter depends upon the fact that person1.Equals(person2) is going to check that person2 isn't null anyway. 后者取决于person1.Equals(person2)将要检查person2是否不为null的事实。 The former would (because it avoids a branch) likely be a slight win when person2 is null, but the latter would likely be a slight win otherwise, and is a bit more concise. person2为null时,前者可能会(因为避免分支)是一个小小的胜利,但否则,后者可能会是一个小小的胜利,并且更加简洁。 I'd generally go for the latter. 我通常会选择后者。

As such, the use of object.Equals() in the example you quote is valid, but it's not the approach I'd recommend. 因此,在您引用的示例中使用object.Equals()是有效的,但这不是我推荐的方法。


Incidentally the override they suggest for object.Equals() I would not recommend at all: 顺便说一句,他们建议对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);
}

If you cut out the first null check then the second one would still catch that case. 如果您剪掉第一个空支票,那么第二个仍然会遇到这种情况。

If you cut out the second null check then the call to Equals() (the overloaded one that takes a Person ) will catch it. 如果切出第二个空检查,则对Equals()的调用(超载了Person那个)将捕获该错误。

As such it should just be: 因此,它应该是:

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

That pattern will serve as the Equals(object) override for any class implementing IEquatable<T> (there might be cases where you wanted to consider the object equal to one of a different type, but those are rare and often wrong even when they are done, so should be perhaps considered a very specialised case). 该模式将用作实现IEquatable<T>任何类的Equals(object)替代(在某些情况下,您可能希望将对象视为另一种类型,但这种情况很少见,即使它们是完成,因此应该被认为是非常专业的案例)。 For any struct you can use: 对于任何结构,您都可以使用:

public override bool Equals(object obj)
{
  return obj is TheStructType && Equals((TheStructType)obj);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM