Equals(item,null)或item == null

使用静态Object.Equals检查null的代码是否比使用==运算符或常规Object.Equals的代码更健壮? 是不是后两者容易被覆盖的方式检查null不能按预期工作(例如,当比较值为空时返回false)?

换句话说,是这样的:

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

比这更强大:

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

我个人发现后者的语法更易于阅读。 在编写处理作者控制范围之外的对象的代码时(例如库)是否应该避免? 是否应该避免(检查为空时)? 这只是头发分裂?


这个问题没有简单的答案。 在我看来,任何说使用一种或另一种的人都会给你提供可怜的建议。

实际上有几种不同的方法可以调用来比较对象实例。 给定两个对象实例ab ,你可以这样写:

  • Object.Equals(a,b)
  • Object.ReferenceEquals(a,b)
  • a.Equals(b)
  • a == b
  • 这些都可以做不同的事情!

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

    Equals的默认实现支持引用类型的引用相等,以及值类型的按位相等。 引用相等意味着被比较的对象引用指的是同一个对象。 按位相等意味着被比较的对象具有相同的二进制表示。

    请注意,派生类型可能会覆盖Equals方法以实现值相等。 值相等意味着比较对象具有相同的值但不同的二进制表示。

    请注意上面的最后一段......我们稍后再讨论这个问题。

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

    a.Equals(b)调用的虚拟实例方法Object ,其类型a可以覆盖做任何事情就是了。 该调用是使用虚拟调度执行的,因此运行的代码取决于a的运行时类型。

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

    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;
    

    所以,是的,使用operator ==检查空值时存在漏洞。 实际上,大多数类型不会重载== - 但是从来没有保证。

    实例方法Equals()在这里没有更好的。 虽然默认实现执行引用/逐位相等检查,但类型可能会覆盖Equals()成员方法,在这种情况下,将会调用此实现。 用户提供的实现可以返回任何想要的结果,即使与null进行比较。

    但是,你问的Object.Equals()的静态版本呢? 这可以最终运行用户代码? 那么,事实证明答案是肯定的。 Object.Equals(a,b)扩展到如下Object.Equals(a,b)行:

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

    你可以自己尝试一下:

    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()的实例版本。

    总之,您获得的比较行为的种类可能会有很大差异,具体取决于您选择调用哪种方法。 然而,这里有一个评论:微软并没有正式记录Object.Equals(a,b)的内部行为。 如果你需要一个熨斗gaurantee比较引用null而没有任何其他代码运行,你想Object.ReferenceEquals()

    Object.ReferenceEquals(item, null);
    

    这种方法使意图得到极端清晰 - 特别期望结果是两个引用相等的参考比较。 使用诸如Object.Equals(a,null)类的东西的好处在于,稍后某人稍后再来并说:

    “嘿,这很尴尬,让我们用: a.Equals(null)或者a == null替换它

    这可能会有所不同。

    但是,让我们在这里注入一些实用主义。 到目前为止,我们已经谈到了不同的比较方式的潜力,以产生不同的结果。 虽然情况确实如此,但某些类型可以安全地编写a == null 。 像StringNullable<T>这样的内置.NET类具有定义好的用于比较的语义。 此外,他们是sealed - 防止通过继承来改变他们的行为。 以下是很常见的(并且是正确的):

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

    这是不必要的(也很难看):

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

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


    if (Equals(item, null))不比if (item == null)更强健,并且我觉得它更难以启动。


    框架指南建议您将Equals视为值相等(检查两个对象是否代表相同的信息,即比较属性),并将==作为引用相等,除了不可变对象之外,您应该重写==价值平等。

    因此,假设这些准则适用于此,请选择语义上合理的语言。 如果你正在处理不可变的对象,并且你希望这两种方法产生相同的结果,为了清晰起见,我会使用==

    链接地址: http://www.djcxy.com/p/76211.html

    上一篇: Equals(item, null) or item == null

    下一篇: Java: clean way to automatically throw UnsupportedOperationException when calling hashCode() and equals()?