等于(item,null)或item == null [英] Equals(item, null) or item == null

查看:172
本文介绍了等于(item,null)或item == null的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是使用静态Object.Equals 进行检查的代码null比使用==运算符或常规Object.Equals ?后两者不是很容易被覆盖,以致于检查null是否无法按预期进行(例如,当比较值 为null时返回false)?

Is code that uses the static Object.Equals to check for null more robust than code that uses the == operator or regular Object.Equals? Aren't the latter two vulnerable to being overridden in such a way that checking for null doesn't work as expected (e.g. returning false when the compared value is null)?

换句话说:

if (Equals(item, null)) { /* Do Something */ }

比这更强大:

if (item == null) { /* Do Something */ }

我个人认为后一种语法更易于阅读。编写可处理作者控制范围之外的对象的代码(例如库)时,应该避免使用它吗?是否应始终避免(在检查null时)?

I personally find the latter syntax easier to read. Should it be avoided when writing code that will handle objects outside the author's control (e.g. libraries)? Should it always be avoided (when checking for null)? Is this just hair-splitting?

推荐答案

这个问题没有简单的答案。在我看来,总是使用一种方法或其他方法会给您不好的建议。

There's no simple answer for this question. Anyone who says always use one or the other is giving you poor advice, in my opinion.

实际上,您可以调用几种不同的方法来比较对象实例。给定两个对象实例 a b ,您可以编写:

There are actually several different methods you can call to compare object instances. Given two object instances a and b, you could write:


  • Object.Equals(a,b)

  • Object。 ReferenceEquals(a,b)

  • a.Equals(b)

  • a == b

  • Object.Equals(a,b)
  • Object.ReferenceEquals(a,b)
  • a.Equals(b)
  • a == b

这些都可以做不同的事情!

Object.Equals(a,b) (默认情况下)将对引用类型执行引用相等性比较,并对值类型执行按位比较。从MSDN文档中:

Object.Equals(a,b) will (by default) perform reference equality comparison on reference types and bitwise comparison on value types. From the MSDN documentation:


Equals
的默认实现支持
引用类型的引用相等和按位相等
用于值类型。引用相等
表示比较
的对象引用引用同一对象。
按位相等意味着被比较的对象
具有相同的二进制
表示形式。

The default implementation of Equals supports reference equality for reference types, and bitwise equality for value types. Reference equality means the object references that are compared refer to the same object. Bitwise equality means the objects that are compared have the same binary representation.

请注意,派生类型可能是
将Equals方法重写为
实现值相等。值
相等意味着被比较的对象
具有相同的值,但具有不同的
二进制表示形式。

Note that a derived type might override the Equals method to implement value equality. Value equality means the compared objects have the same value but different binary representations.

请注意上面的最后一段……我们稍后再讨论。

Note the last paragraph above ... we'll discuss this a bit later.

Object.ReferenceEquals(a,b) 仅执行引用相等比较。如果传递的类型是装箱的值类型,则结果始终为 false

a.Equals(b) 调用 Object 的虚拟实例方法,该方法的类型为 可以覆盖它想要执行的任何操作。该调用是使用虚拟调度执行的,因此运行的代码取决于 a 的运行时类型。

a.Equals(b) calls the virtual instance method of Object, which the type of a could override to do anything it wants. The call is performed using virtual dispatch, so the code that runs depends on the runtime type of a.

a == b 调用 a 。如果该运算符的实现在 a b 上调用实例方法,则它也可能取决于运行时类型的参数。由于分派基于表达式中的类型,因此以下内容可能会产生不同的结果:

a == b invokes the static overloaded operator of the **compile-time type* of a. If the implementation of that operator invokes instance methods on either a or b, it may also depend on the runtime types of the parameters. Since the dispatch is based on the types in the expression, the following may yield different results:

Frog aFrog = new Frog();
Frog bFrog = new Frog();
Animal aAnimal = aFrog;
Animal bAnimal = bFrog;
// not necessarily equal...
bool areEqualFrogs = aFrog == bFrog;
bool areEqualAnimals = aAnimal = bAnimal;

因此,是的,使用可以检查是否存在空值运算符== 实际上,大多数类型不会重载 == -但从来没有保证。

So, yes, there is vulnerability for check for nulls using operator ==. In practice, most types do not overload == - but there's never a guarantee.

实例方法 Equals()在这里再好不过了。当默认实现执行引用/按位相等性检查时,类型有可能覆盖 Equals()成员方法,在这种情况下将调用此实现。用户提供的实现可以返回所需的内容,即使与null进行比较也是如此。

The instance method Equals() is no better here. While the default implementation performs reference/bitwise equality checks, it is possible for a type to override the Equals() member method, in which case this implementation will be called. A user supplied implementation could return whatever it wants, even when comparing to null.

但是 Object.Equals()您问?这样可以结束运行用户代码吗?好吧,事实证明答案是肯定的。 Object.Equals(a,b)的实现扩展为:

But what about the static version of Object.Equals() you ask? Can this end up running user code? Well, it turns out that the answer is YES. The implementation of Object.Equals(a,b) expands to something along the lines of:

((object)a == (object)b) || (a != null && b != null && a.Equals(b))

您可以自己尝试以下操作:

You can try this for yourself:

class Foo {
    public override bool Equals(object obj) { return true; }  }

var a = new Foo();
var b = new Foo();
Console.WriteLine( Object.Equals(a,b) );  // outputs "True!"

结果是,可能出现以下语句: Object.Equals(a ,b)在调用中两种类型都不为 null 时运行用户代码。请注意, Object.Equals(a,b) 不会调用 Equals()

As a consequence, it's possible for the statement: Object.Equals(a,b) to run user code when neither of the types in the call are null. Note that Object.Equals(a,b) does not call the instance version of Equals() when either of the arguments is null.

简而言之,根据选择的调用方法,您获得的比较行为的种类可能会有很大不同。但是,这里有一条评论:Microsoft尚未正式记录 Object.Equals(a,b)的内部行为。 如果需要在不运行任何其他代码的情况下将引用与null进行比较的严格保证,则需要 Object.ReferenceEquals()

In short, the kind of comparison behavior you get can vary significantly, depending on which method you choose to call. One comment here, however: Microsoft doesn't officially document the internal behavior of Object.Equals(a,b). If you need an iron clad gaurantee of comparing a reference to null without any other code running, you want Object.ReferenceEquals():

Object.ReferenceEquals(item, null);

此方法使意图极其清晰-您特别希望结果是两个引用的比较供参考平等。与使用 Object.Equals(a,null)之类的东西相比,这样做的好处是,某人以后再来说:

This method makes the intent extremently clear - you are specifically expecting the result to be the comparison of two references for reference equality. The benefit here over using something like Object.Equals(a,null), is that it's less likely that someone will come along later and say:

嘿,这很尴尬,让我们将其替换为: a.Equals(null) a == null

可能会有所不同。

但是,让我们在这里注入一些实用主义。到目前为止,我们已经讨论了使用不同比较方式来产生不同结果的可能性。虽然确实如此,但是在某些类型中可以安全地编写 a == null 。内置的.NET类,例如 String Nullable< T& 具有明确定义的语义以便进行比较。此外,它们是密封的-防止通过继承对其行为进行任何更改。 ):

Let's inject some pragmatism here, however. So far we've talked about the potential for different modalities of comparison to yield different results. While this is certainly the case, there are certain types where it's safe to write a == null. Built-in .NET classes like String and Nullable<T> have well defined semantics for comparison. Furthermore, they are sealed - preventing any change to their behavior through inheritance. The following is quite common (and correct):

string s = ...
if( s == null ) { ... }

不必(而且很丑)写:

if( ReferenceEquals(s,null) ) { ... }

因此,在某些有限的情况下,使用 == 是安全且适当的。

So in certain limited cases, using == is safe, and appropriate.

这篇关于等于(item,null)或item == null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆