Object.Equals 方法 (Object)

2013/12/13

确定指定的 Object 是否等于当前的 Object

Namespace:  System
程序集:  mscorlib(位于 mscorlib.dll 中)

public virtual bool Equals(
	Object obj
)

参数

obj
类型: System.Object
与当前的 Object 进行比较的 Object

返回值

类型: System.Boolean
如果指定的 Object 等于当前的 Object,则为 true;否则为 false

Equals 的默认实现支持引用相等性(对于引用类型)和按位相等性(对于值类型)。引用相等性是指进行比较的多个对象引用所引用的是同一个对象。按位相等性是指进行比较的多个对象具有相同的二进制表示形式。

请注意,派生类型可以重写 Equals 方法以实现值相等性。值相等性是指所比较的对象具有相同的值,即使它们具有不同的二进制表示形式也是如此。例如,请考虑两个分别表示数字 1.10 和 1.1000 的 Decimal 对象。Decimal 对象不具有按位相等性,因为它们具有不同的二进制表示形式,因此会考虑不同数量的尾随零。但是,这些对象具有值相等性,因为在进行比较时尾随零无关紧要,数字 1.10 和 1.1000 被视为相等。

对实现者的说明

此方法可由派生类重写。例如,如果两个对象表示相同的值,则许多基数据类型返回 true;否则返回 false

此方法仅比较基元和对象。若要比较更复杂的结构(如对象数组),必须重写该方法。

下面的语句对于 Equals 方法的所有实现均必须为真。在列表中,x、y 和 z 表示不为 null 的对象引用。

  • 除涉及浮点型的情况外,x.Equals(x) 都返回 true。请参见 IEC 60559:1989, Binary Floating-point Arithmetic for Microprocessor Systems。

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

  • 如果 x 和 y 都为 NaN,则 x.Equals(y) 返回 true

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

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

  • x.Equals(null) 返回 false

有关属于 Equals 方法的其他必需行为,请参见 GetHashCode

Equals 的实现必须不引发异常。

对于某些类型的对象,最好让 Equals 测试值相等性而非引用相等性。如果两个对象具有相同的“值”,那么即使它们不是同一实例,这样的 Equals 实现仍返回 true。类型实施者决定对象的“值”的构成,但这通常是存储在对象的实例变量中的部分或全部数据。例如,String 的值基于字符串的字符;对于两个按同样的顺序包含完全相同的字符的字符串实例,String 类的 Equals 方法返回 true

实现 IComparable 的类型必须重写 Equals

重写 Equals 的类型还必须重写 GetHashCode

如果编程语言支持运算符重载,并且您选择了重载给定类型的相等运算符,则该类型必须重写 Equals 方法。这样的 Equals 方法实现必须返回与相等运算符相同的结果。遵照此准则有助于确保使用 Equals 的类库代码的行为方式与应用程序代码使用的相等运算符的行为方式一致。

下面是针对实现值类型的准则:

  • 考虑重写 Equals,以便在 ValueType 上获得比 Equals 的默认实现所提供的性能增强的性能。

  • 如果重写 Equals 并且语言支持运算符重载,则必须重载值类型的相等运算符。

下面是针对实现引用类型的准则:

  • 如果引用类型的语义是基于该类型表示某个(些)值的事实,则考虑对该类型重写 Equals

  • 即使大多数引用类型重写 Equals,它们也必须不能重载相等运算符。但是,如果实现的引用类型想要具有值语义(如复杂的数字类型),则必须重写相等运算符。

下面的代码示例将当前的实例与另一个对象进行比较。


using System;

public class Example
{
   public static void Demo(System.Windows.Controls.TextBlock outputBlock)
   {
      Object Obj1 = new Object();
      Object Obj2 = new Object();
      outputBlock.Text += Obj1.Equals(Obj2) + "\n"; //===> false
      Obj2 = Obj1;
      outputBlock.Text += Obj1.Equals(Obj2) + "\n"; //===> true
   }
}


下面的示例显示一个 Point 类,该类重写 Equals 方法以提供值相等和一个从 Point 派生的 Point3D 类。由于 PointEquals 重写方法是引入值相等性的继承链中的第一项,因此不调用基类的 Equals 方法(从 Object 继承并检查引用相等性)。但是,因为 Point 以提供值相等性的方式实现 Equals,所以 Point3D.Equals 调用 Point.Equals


using System;

class Point : Object
{
   protected int x, y;

   public Point()
   {
      this.x = 0;
      this.y = 0;
   }

   public Point(int X, int Y)
   {
      this.x = X;
      this.y = Y;
   }

   public override bool Equals(Object obj)
   {
      //Check for null and compare run-time types.
      if (obj == null || GetType() != obj.GetType()) return false;
      Point p = (Point)obj;
      return (x == p.x) && (y == p.y);
   }

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


class Point3D : Point
{
   int z;

   public Point3D(int X, int Y, int Z)
   {
      this.x = X;
      this.y = Y;
      this.z = Z;
   }

   public override bool Equals(Object obj)
   {
      return base.Equals(obj) && z == ((Point3D)obj).z;
   }

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

class Example
{

   public static void Demo(System.Windows.Controls.TextBlock outputBlock)
   {
      Point point2D = new Point(5, 5);
      Point3D point3Da = new Point3D(5, 5, 2);
      Point3D point3Db = new Point3D(5, 5, 2);

      if (!point2D.Equals(point3Da))
      {
         outputBlock.Text += "point2D does not equal point3Da." + "\n";
      }
      if (!point3Db.Equals(point2D))
      {
         outputBlock.Text += String.Format("Likewise, point3Db does not equal point2D.") + "\n";
      }
      if (point3Da.Equals(point3Db))
      {
         outputBlock.Text += String.Format("However, point3Da equals point3Db.") + "\n";
      }

   }
}
// ----------------------------------
// Output should be:
// 
// point2D does not equal point3Da.
// Likewise, point3Db does not equal point2D.
// However, point3Da equals point3Db.


Point.Equals 方法检查 obj 参数是否不为 null,并检查它引用的实例是否与该对象具有相同的类型。如果这两项检查中有任何一项失败,则方法返回 false

Equals 方法使用 GetType 确定两个对象的运行时类型是否相同。(注意,这里不使用 typeof,因为它返回静态类型)。如果方法使用了 obj is Point 的检查形式,则在 objPoint 的派生类实例的情况下,即使 obj 和当前实例的运行时类型不同,该检查也返回 true。验证了两个对象的类型相同后,该方法将 obj 转换为 Point 类型,并返回两个对象的实例变量的比较结果。

Point3D.Equals 中,完成任何其他事情之前首先调用继承的 Equals 方法;继承的 Equals 方法将检查 obj 是否不为 nullobj 是否是与此对象相同的类的实例,以及继承的实例变量是否匹配。只有当继承的 Equals 返回 true 时,该方法才比较在派生类中引入的实例变量。具体说来,除非 obj 已被确定为是 Point3D 类型或者是 Point3D 的派生类,否则不执行到 Point3D 的转换。

在前面的示例中,使用相等运算符来比较各个实例变量。在某些情况下,适合使用 Equals 方法来比较 Equals 实现中的实例变量,如下面的示例所示。


using System;

class Rectangle
{
   Point a, b;

   public Rectangle(int upLeftX, int upLeftY, int downRightX, int downRightY)
   {
      this.a = new Point(upLeftX, upLeftY);
      this.b = new Point(downRightX, downRightY);
   }

   public override bool Equals(Object obj)
   {
      // Performs an equality check on two rectangles (Point object pairs).
      if (obj == null || GetType() != obj.GetType()) return false;
      Rectangle r = (Rectangle)obj;
      //Uses Equals to compare variables.
      return a.Equals(r.a) && b.Equals(r.b);
   }

   public override int GetHashCode()
   {
      return a.GetHashCode() ^ b.GetHashCode();
   }
}

// Class Point added for clean compile
class Point
{
   private int x;
   private int y;

   public Point(int X, int Y)
   {
      this.x = X;
      this.y = Y;
   }

   public override bool Equals(Object obj)
   {
      // Performs an equality check on two points (integer pairs).
      if (obj == null || GetType() != obj.GetType()) return false;
      Point p = (Point)obj;
      return (x == p.x) && (y == p.y);
   }

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

}

class Example
{
   public static void Demo(System.Windows.Controls.TextBlock outputBlock)
   {

      Rectangle r1 = new Rectangle(0, 0, 100, 200);
      Rectangle r2 = new Rectangle(0, 0, 100, 200);
      Rectangle r3 = new Rectangle(0, 0, 150, 200);

      if (r1.Equals(r2))
      {
         outputBlock.Text += "Rectangle r1 equals rectangle r2!" + "\n";
      }
      if (!r2.Equals(r3))
      {
         outputBlock.Text += "But rectangle r2 does not equal rectangle r3." + "\n";
      }
   }
}
// ------------------------------
// Output should be:
// Rectangle r1 equals rectangle r2!
// But rectangle r2 does not equal rectangle r3.


有些编程语言比如 C# 和 Visual Basic 是支持运算符重载的。当类型重载相对运算符时,它也必须重写 Equals,以提供同样的功能。一般是通过根据重载的相等运算符编写 Equals 方法来达到这一目的,如下面的代码示例所示。


using System;

public struct Complex
{
   public double re, im;

   public override bool Equals(Object obj)
   {
      return obj is Complex && this == (Complex)obj;
   }

   public override int GetHashCode()
   {
      return re.GetHashCode() ^ im.GetHashCode();
   }

   public static bool operator ==(Complex x, Complex y)
   {
      return x.re == y.re && x.im == y.im;
   }

   public static bool operator !=(Complex x, Complex y)
   {
      return !(x == y);
   }
}

class Example
{

   public static void Demo(System.Windows.Controls.TextBlock outputBlock)
   {
      Complex cmplx1, cmplx2;

      cmplx1.re = 4.0;
      cmplx1.im = 1.0;

      cmplx2.re = 2.0;
      cmplx2.im = 1.0;

      if (cmplx1 != cmplx2)
         Console.WriteLine("The two objects are not equal.");
      if (! cmplx1.Equals(cmplx2))
         Console.WriteLine("The two objects are not equal.");

      cmplx2.re = 4.0;

      if (cmplx1 == cmplx2) 
         Console.WriteLine("The two objects are now equal!");
      if (cmplx1.Equals(cmplx2)) 
         Console.WriteLine("The two objects are now equal!");
   }
}
// The example displays the following output:
//       The two objects are not equal.
//       The two objects are not equal.
//       The two objects are now equal!
//       The two objects are now equal!


由于 Complex 为值类型,所以不能从该类型派生;因此,Equals 方法不需要比较每个对象的 GetType 结果,而是可以改用 is 运算符来检查 obj 参数的类型。

Windows Phone OS

受以下版本支持: 8.0, 7.1, 7.0

Windows Phone

显示:
© 2014 Microsoft