• Equals() 和 运算符 == 重载准则 (C# 编程指南)


    C# 中有两种不同的相等:引用相等和值相等。值相等是大家普遍理解的意义上的相等:它意味着两个对象包含相同的值。例如,两个值为 2 的整数具有值相等性。引用相等意味着要比较的不是两个对象,而是两个对象引用,这两个对象引用引用的是同一个对象。这可以通过简单的赋值来实现,如下面的示例所示:

    System.Object a = new System.Object();
    System.Object b
    = a;
    System.Object.ReferenceEquals(a, b);
    //returns true

    在上面的代码中,只存在一个对象,但存在对该对象的多个引用:ab。由于它们引用的是同一个对象,因此具有引用相等性。如果两个对象具有引用相等性,则它们也具有值相等性,但是值相等性不能保证引用相等性。

    若要检查引用相等性,应使用 ReferenceEquals。若要检查值相等性,应使用 EqualsEquals

    重写 Equals

    Equals 是一个虚方法,允许任何类重写其实现。表示某个值(本质上可以是任何值类型)或一组值(如复数类)的任何类都应该重写 Equals。如果类型要实现 IComparable,则它应该重写 Equals

    Equals 的新实现应该遵循 Equals 的所有保证:

    • x.Equals(x) 返回 true。

    • x.Equals(y) 与 y.Equals(x) 返回相同的值。

    • 如果 (x.Equals(y) && y.Equals(z)) 返回 true,则 x.Equals(z) 返回 true。

    • 只要不修改 x 和 y 所引用的对象,x.Equals(y) 的后续调用就返回相同的值。

    • x.Equals(null) 返回 false。

    Equals 的新实现不应该引发异常。建议重写 Equals 的任何类同时也重写 System.Object.GetHashCode。除了实现 Equals(对象)外,还建议所有的类为自己的类型实现 Equals(类型)以增强性能。例如:

     

    class TwoDPoint : System.Object
    {
    public readonly int x, y;

    public TwoDPoint(int x, int y) //constructor
    {
    this.x = x;
    this.y = y;
    }

    public override bool Equals(System.Object obj)
    {
    // If parameter is null return false.
    if (obj == null)
    {
    return false;
    }

    // If parameter cannot be cast to Point return false.
    TwoDPoint p = obj as TwoDPoint;
    if ((System.Object)p == null)
    {
    return false;
    }

    // Return true if the fields match:
    return (x == p.x) && (y == p.y);
    }

    public bool Equals(TwoDPoint p)
    {
    // If parameter is null return false:
    if ((object)p == null)
    {
    return false;
    }

    // Return true if the fields match:
    return (x == p.x) && (y == p.y);
    }

    public override int GetHashCode()
    {
    return x ^ y;
    }
    }

    可调用基类的 Equals 的任何派生类在完成其比较之前都应该这样做。在下面的示例中,Equals 调用基类 Equals,后者将检查空参数并将参数的类型与派生类的类型做比较。这样就把检查派生类中声明的新数据字段的任务留给了派生类中的 Equals 实现:

     

    class ThreeDPoint : TwoDPoint
    {
    public readonly int z;

    public ThreeDPoint(int x, int y, int z)
    :
    base(x, y)
    {
    this.z = z;
    }

    public override bool Equals(System.Object obj)
    {
    // If parameter cannot be cast to ThreeDPoint return false:
    ThreeDPoint p = obj as ThreeDPoint;
    if ((object)p == null)
    {
    return false;
    }

    // Return true if the fields match:
    return base.Equals(obj) && z == p.z;
    }

    public bool Equals(ThreeDPoint p)
    {
    // Return true if the fields match:
    return base.Equals((TwoDPoint)p) && z == p.z;
    }

    public override int GetHashCode()
    {
    return base.GetHashCode() ^ z;
    }
    }

    Overriding Operator ==

    默认情况下,运算符 == 通过判断两个引用是否指示同一对象来测试引用是否相等,因此引用类型不需要实现运算符 == 就能获得此功能。当类型不可变时,意味着实例中包含的数据不可更改,此时通过重载运算符 == 来比较值是否相等而不是比较引用是否相等可能会很有用,因为作为不可变的对象,只要它们具有相同的值,就可以将它们看作是相同的。建议不要在非不可变类型中重写运算符 ==

    重载的运算符 == 实现不应引发异常。重载运算符 == 的任何类型还应重载运算符 !=。例如:

     

    //add this code to class ThreeDPoint as defined previously
    //
    public static bool operator ==(ThreeDPoint a, ThreeDPoint b)
    {
    // If both are null, or both are same instance, return true.
    if (System.Object.ReferenceEquals(a, b))
    {
    return true;
    }

    // If one is null, but not both, return false.
    if (((object)a == null) || ((object)b == null))
    {
    return false;
    }

    // Return true if the fields match:
    return a.x == b.x && a.y == b.y && a.z == b.z;
    }

    public static bool operator !=(ThreeDPoint a, ThreeDPoint b)
    {
    return !(a == b);
    }

     

    注意:------------------------

    运算符 == 的重载中的常见错误是使用 (a == b)(a == null)(b == null) 来检查引用相等性。这会导致调用重载的运算符 ==,从而导致无限循环。应使用 ReferenceEquals 或将类型强制转换为 Object 来避免无限循环。

    ------------------------------


    返回导读目录,阅读更多随笔



    分割线,以下为博客签名:

    软件臭虫情未了
    • 编码一分钟
    • 测试十年功


    随笔如有错误或不恰当之处、为希望不误导他人,望大侠们给予批评指正。

  • 相关阅读:
    JAVA面试必备笔记:必须掌握的核心技能点
    这里有份最全的微服务,看完你就通关了
    大厂流出:JAVA面试必问面试题及答案
    阿里面试官:请叙述一下HTTP和HTTPS的区别
    [LeetCode] Serialize and Deserialize BST
    [LeetCode] Serialize and Deserialize Binary Tree
    [LeetCode] Next Greater Element II
    [LeetCode] Next Greater Element I
    [MySQL] ACID
    [Linux] linux下生成静态库和动态库
  • 原文地址:https://www.cnblogs.com/08shiyan/p/1983257.html
Copyright © 2020-2023  润新知