代码之家  ›  专栏  ›  技术社区  ›  Joseph Sturtevant

等于(item,null)或item==null

  •  38
  • Joseph Sturtevant  · 技术社区  · 14 年前

    是使用 static Object.Equals 检查空值比使用==运算符或 regular Object.Equals ? 后两种方法是否容易被重写,以至于检查null不能按预期工作(例如,在比较值时返回false) 空)?

    换句话说,这是:

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

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

    我个人认为后一种语法更容易阅读。在编写处理作者无法控制的对象(例如库)的代码时,是否应该避免这种情况?是否应始终避免(在检查null时)?这只是头发分裂吗?

    5 回复  |  直到 14 年前
        1
  •  76
  •   LBushkin    14 年前

    在我看来,任何人说总是用其中一个或另一个给你的建议都是拙劣的。

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

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

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

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

    Equals的默认实现 支持的引用相等 引用类型和位相等 是指 位相等表示对象 被比较的具有相同的二进制

    请注意,派生类型可能 重写Equals方法以 相等是指比较对象

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

    Object.ReferenceEquals对象(甲、乙) false

    a、 等于(b) 调用的虚拟实例方法 Object ,它是 可以做任何它想做的事。调用是使用虚拟分派执行的,因此运行的代码取决于

    a==b 调用的**编译时类型*的静态重载运算符 . 如果该操作符的实现调用 b

    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() 等于() 成员方法,在这种情况下将调用此实现。用户提供的实现可以返回它想要的任何内容,即使在与null比较时也是如此。

    但是静态版本的呢 Object.Equals() 对象。等于(甲、乙) 扩展到以下内容:

    ((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!"
    

    对象。等于(甲、乙) 在调用中的两种类型都不可用时运行用户代码 null . 请注意 对象。等于(甲、乙) 调用的实例版本 等于() 当任一参数为null时。

    简而言之,根据您选择调用的方法,您得到的比较行为可能会有很大的不同。不过,这里有一条评论:微软并没有正式记录微软的内部行为 . 如果您需要一个铁板钉钉的gaurantee,在不运行任何其他代码的情况下将引用与null进行比较,那么 Object.ReferenceEquals() :

    Object.ReferenceEquals(item, null);
    

    这个方法使意图非常清楚-您特别希望结果是比较两个引用以获得引用相等。使用类似 Object.Equals(a,null) ,也就是说不太可能有人后来会说:

    “嘿,这太尴尬了,换成: a.Equals(null) a == null

    可能会有所不同。

    不过,让我们在这里注入一些实用主义。 a==空 . 内置.NET类,如 String Nullable<T> 有定义良好的语义进行比较。此外,它们是 sealed -防止通过继承对其行为进行任何更改。以下是很常见的(也是正确的):

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

    没有必要(而且很难看)写:

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

    == 是安全的,合适的。

        2
  •  5
  •   Michael Burr    14 年前

    if (Equals(item, null)) if (item == null) ,我发现开机更让人困惑。

        3
  •  3
  •   ToolmakerSteve    11 年前

    当您要测试标识(内存中的相同位置)时:

    ReferenceEquals(a, b)

    但要确保你真的想要身份测试。考虑以下几点:

    ReferenceEquals(new String("abc"), new String("abc"))

    它回来了 false

    Object.Equals(new String("abc"), new String("abc"))

    (new String("abc")) == (new String("abc"))

    两者都返回 true

    如果你期待的是 在这种情况下,您需要的是相等性测试,而不是身份测试。


    当您要测试相等性(相同内容)时:

    • “使用” a == b “如果编译器不抱怨。

    • 如果拒绝(如果变量a的类型没有定义“==”运算符),则使用 Object.Equals(a, b)

    • 如果 你在哪里 已知a不为空 ,则您可以使用更具可读性的“ a.Equals(b) ". 例如this.Equals(b) “是安全的。或者如果“a”是在构造时初始化的字段,并且如果传入null作为要在该字段中使用的值,则构造函数抛出异常。

    现在,要解决最初的问题:

    问:这些代码是否容易在某些类中被重写,而代码不能正确处理null,从而导致异常?

    A:是的。获得100%安全相等性测试的唯一方法是自己对空值进行预测试。

    但你应该吗?这个bug将出现在那个(假设的未来坏类)中,它将是一种直接的失败类型。易于调试和修复(由提供类的任何人)。我怀疑这是一个经常发生的问题,或者当它确实发生时会持续很长时间。

    更详细的A: 对象。等于(甲、乙) 最有可能在写作不好的课堂上工作。如果“a”为空,对象类将自己处理它,因此没有风险。如果“b”为null,则“a”的动态(运行时而非编译时)类型决定调用什么“Equals”方法。被调用的方法只需在“b”为null时正常工作。除非被调用的方法写得非常糟糕,否则它要做的第一步就是确定“b”是否是它能理解的类型。

    所以呢 对象。等于(甲、乙)

        4
  •  2
  •   mqp    14 年前

    这个 framework guidelines 建议你 Equals == 作为引用相等,但不可变对象除外,您可能应该重写这些对象 ==

    因此,假设这些准则在这里适用,选择语义上合理的。如果您处理的是不可变对象,并且您希望这两种方法产生相同的结果,那么我将使用 ==

        5
  •  1
  •   Daniel Pratt    14 年前

    关于“…编写代码来处理作者控制之外的对象…”,我要指出 Object.Equals 以及 == 在编译时 基于静态类型。换句话说,外部库无法为编译后的代码提供不同版本的例程。

        6
  •  0
  •   Dan    4 年前

    当我试图比较对象的唯一Id时,我在这里结束了,这些对象本身可能是空的。我们发现先对缺失的数据进行插补,然后再进行比较更容易。

    Guid currentId = (Object1 == null) ? Guid.Empty : Object1.Id;
    Guid newId = (Object2 == null) ? Guid.Empty : Object2.Id;
    If (currentId == newId)
    {
        //do happyface
    }
    else
    {
       //do sadface
    }