本文由机器翻译。若要查看英语原文,请勾选“英语”复选框。 也可将鼠标指针移到文本上,在弹出窗口中显示英语原文。
翻译
英语

Object.Equals 方法 (Object)

 

确定指定的对象是否等于当前对象。

命名空间:   System
程序集:  mscorlib(位于 mscorlib.dll)

public virtual bool Equals(
	object obj
)

参数

obj
Type: System.Object

要与当前对象进行比较的对象。

返回值

Type: System.Boolean

如果指定的对象等于当前对象,则为 true,否则为 false

当前实例进行比较的类型和obj参数取决于当前实例是否为引用类型或值类型。

  • 如果当前实例是引用类型,Equals(Object)方法测试引用相等性,并调用Equals(Object)方法等效于调用ReferenceEquals方法。 引用相等性意味着进行比较的对象变量引用同一个对象。 下面的示例阐释了这种比较的结果。 它定义Person类,该类是引用类型,并调用Person类构造函数来实例化两个新Person对象,person1aperson2,其中具有相同的值。 它还会将分配person1a给另一个对象变量, person1b 如示例所示,输出person1aperson1b由于它们都引用同一个对象是否相等。 但是,person1aperson2是否不相等,尽管它们具有相同的值。

    using System;
    
    // Define a reference type that does not override Equals.
    public class Person
    {
       private string personName;
    
       public Person(string name)
       {
          this.personName = name;
       }
    
       public override string ToString()
       {
          return this.personName;
       }
    }
    
    public class Example
    {
       public static void Main()
       {
          Person person1a = new Person("John");
          Person person1b = person1a;
          Person person2 = new Person(person1a.ToString());
    
          Console.WriteLine("Calling Equals:"); 
          Console.WriteLine("person1a and person1b: {0}", person1a.Equals(person1b));               
          Console.WriteLine("person1a and person2: {0}", person1a.Equals(person2));  
    
          Console.WriteLine("\nCasting to an Object and calling Equals:");
          Console.WriteLine("person1a and person1b: {0}", ((object) person1a).Equals((object) person1b));
          Console.WriteLine("person1a and person2: {0}", ((object) person1a).Equals((object) person2)); 
       }
    }
    // The example displays the following output:
    //       person1a and person1b: True
    //       person1a and person2: False
    //       
    //       Casting to an Object and calling Equals:
    //       person1a and person1b: True
    //       person1a and person2: False
    
  • 如果当前实例是值类型,Equals(Object)方法测试值是否相等。 值相等性意味着︰

    • 两个对象均为相同的类型。 如下面的示例所示,Byte的值为 12 的对象不等于Int32具有其值为 12,因为两个对象具有不同的运行时类型的对象。

      using System;
      
      public class Example
      {
         public static void Main()
         {
            byte value1 = 12;
            int value2 = 12;
      
            object object1 = value1;
            object object2 = value2;
      
            Console.WriteLine("{0} ({1}) = {2} ({3}): {4}",
                              object1, object1.GetType().Name,
                              object2, object2.GetType().Name,
                              object1.Equals(object2));
         }
      }
      // The example displays the following output:
      //        12 (Byte) = 12 (Int32): False
      
    • 两个对象的公共和私有字段的值相等。 下面的示例测试的值相等。 它定义Person结构,这是值类型,并调用Person类构造函数来实例化两个新Person对象,person1person2,其中具有相同的值。 如示例输出所示,虽然两个对象变量引用不同的对象,但person1person2是否相等的因为它们具有相同的值为私有personName字段。

      using System;
      
      // Define a value type that does not override Equals.
      public struct Person
      {
         private string personName;
      
         public Person(string name)
         {
            this.personName = name;
         }
      
         public override string ToString()
         {
            return this.personName;
         }
      }
      
      public struct Example
      {
         public static void Main()
         {
            Person person1 = new Person("John");
            Person person2 = new Person("John");
      
            Console.WriteLine("Calling Equals:"); 
            Console.WriteLine(person1.Equals(person2)); 
      
            Console.WriteLine("\nCasting to an Object and calling Equals:");
            Console.WriteLine(((object) person1).Equals((object) person2));  
         }
      }
      // The example displays the following output:
      //       Calling Equals:
      //       True
      //       
      //       Casting to an Object and calling Equals:
      //       True
      

因为Object类是.NET Framework 中的所有类型的基类Object.Equals(Object)方法提供对于所有其他类型的默认相等比较。 但是,类型通常替代Equals方法来实现值是否相等。 有关详细信息,请参阅说明调用方和说明的继承者节。

当调用Equals(Object)中的类上的方法重载Windows 运行时,它不会覆盖的类提供的默认行为Equals(Object) 这是由 .NET Framework 为 Windows 运行时 提供的支持的一部分 (请参见.NET Framework 对 Windows 应用商店应用程序和 Windows 运行时的支持情况)。 中的类Windows 运行时不继承Object,并且不要实施Equals(Object)方法。 但是,它们会显示为具有ToStringEquals(Object),和GetHashCode方法在 C# 或 Visual Basic 代码中,使用它们以及.NET Framework 为这些方法提供的默认行为时。

System_CAPS_note说明

Windows 运行时用 C# 或 Visual Basic 编写的类可以重写Equals(Object)方法重载。

经常重写派生的类Object.Equals(Object)方法来实现值是否相等。 此外,类型也经常提供到另一个强类型的重载Equals方法,通常通过实现IEquatable<T>接口。 当调用Equals方法来测试相等性,你应知道的当前实例是否替代Object.Equals并了解如何对特定调用Equals方法处于已解决状态。 否则为你可能不同于你预期的相等性执行测试,并且该方法可能返回了意外的值。

下面的示例进行了这方面的演示。 它实例化三个StringBuilder使用相同的字符串对象,然后在将四个调用Equals方法。 第一种方法调用返回true,和剩余的三个返回false

using System;
using System.Text;

public class Example
{
   public static void Main()
   {
      StringBuilder sb1 = new StringBuilder("building a string...");
      StringBuilder sb2 = new StringBuilder("building a string...");

      Console.WriteLine("sb1.Equals(sb2): {0}", sb1.Equals(sb2));
      Console.WriteLine("((Object) sb1).Equals(sb2): {0}", 
                        ((Object) sb1).Equals(sb2));
      Console.WriteLine("Object.Equals(sb1, sb2): {0}",
                        Object.Equals(sb1, sb2));      

      Object sb3 = new StringBuilder("building a string...");
      Console.WriteLine("\nsb3.Equals(sb2): {0}", sb3.Equals(sb2));                              
   }
}
// The example displays the following output:
//       sb1.Equals(sb2): True
//       ((Object) sb1).Equals(sb2): False
//       Object.Equals(sb1, sb2): False
//
//       sb3.Equals(sb2): False

在第一个的情况下,强类型化StringBuilder.Equals(StringBuilder)调用方法重载,它的值是否相等,测试。 因为字符串分配给两个StringBuilder对象是否相等,则该方法返回true 但是,StringBuilder不重写Object.Equals(Object) 因此,当StringBuilder对象强制转换为Object,当StringBuilder实例分配给类型的变量的Object,以及何时Object.Equals(Object, Object)方法传递两个StringBuilder对象,则默认Object.Equals(Object)调用方法。 因为StringBuilder是引用类型,该属性等同于传递两个StringBuilder对象添加到ReferenceEquals方法。 尽管所有三个StringBuilder对象包含相同的字符串,则指三个不同的对象。 因此,这些三个方法调用返回false

你可以通过调用比较当前对象与另一个对象引用相等性ReferenceEquals方法。 在 Visual Basic 中,你还可以使用is关键字 (例如, If Me Is otherObject Then ...)。

当你定义你自己的类型时,该类型继承定义的功能Equals方法与其基类型。 下表列出的默认实现Equals为主要类别的.NET Framework 中的类型的方法。

类型类别

所定义的相等

注释

直接从派生类Object

Object.Equals(Object)

引用相等性;等效于调用Object.ReferenceEquals

结构

ValueType.Equals

值相等。直接逐字节比较或按字段比较使用反射。

枚举

Enum.Equals

值必须具有相同的枚举类型和相同的基础值。

委托

MulticastDelegate.Equals

委托必须具有相同的调用列表的相同类型。

接口

Object.Equals(Object)

引用相等性。

对于值类型,则应始终重写Equals,因为测试是否相等依赖于反射提供性能不佳。 此外可以重写的默认实现Equals对于引用类型来测试而不是引用相等性的值是否相等并定义值相等性的精确意义。 此类实现Equals返回true如果两个对象具有相同的值,即使它们不是同一个实例。 该类型的实施者决定构成对象的值,但它通常是部分或全部存储的数据的对象的实例变量中。 例如,值为String对象所基于的字符字符串;String.Equals(Object)方法重写Object.Equals(Object)方法以返回true任何两个字符串包含相同的顺序中的相同字符的实例。

下面的示例演示如何重写Object.Equals(Object)方法来测试的值是否相等。 它将重写Equals方法Person类。 如果Person接受相等性,其基类实现两个Person对象将引用单个对象,它们才相等。 但是,在这种情况下,两个Person对象是否相等,如果它们具有相同的值Person.Id属性。

public class Person
{
   private string idNumber;
   private string personName;

   public Person(string name, string id)
   {
      this.personName = name;
      this.idNumber = id;
   }

   public override bool Equals(Object obj)
   {
      Person personObj = obj as Person; 
      if (personObj == null)
         return false;
      else
         return idNumber.Equals(personObj.idNumber);
   }

   public override int GetHashCode()
   {
      return this.idNumber.GetHashCode(); 
   }
}

public class Example
{
   public static void Main()
   {
      Person p1 = new Person("John", "63412895");
      Person p2 = new Person("Jack", "63412895");
      Console.WriteLine(p1.Equals(p2));
      Console.WriteLine(Object.Equals(p1, p2));
   }
}
// The example displays the following output:
//       True
//       True

除了重写Equals,你可以实现IEquatable<T>接口,以提供强类型化的测试相等性。

以下语句必须为 true 的所有实现Equals(Object)方法。 在列表中, xy,和z表示不是对象引用null

  • x.Equals(x)返回true,涉及浮点类型的情况除外。 请参阅 ISO/IEC/IEEE 60559:2011,信息技术-微处理器系统-浮点运算。

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

  • x.Equals(y)返回true如果这两个xyNaN

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

  • 对连续调用x.Equals(y)返回相同的值,只要引用对象xy不会修改。

  • x.Equals(null) 返回 false

实现Equals必须不引发异常; 它们应始终会返回值。 例如,如果objnullEquals方法应返回false而不是引发ArgumentNullException

重写时,请遵循以下准则Equals(Object):

  • 类型实现IComparable必须重写Equals(Object)

  • 类型重写Equals(Object)还必须重写GetHashCode; 否则为哈希表可能无法正常工作。

  • 你应该考虑实施IEquatable<T>接口以支持强类型化测试是否相等。IEquatable<T>.Equals实现应返回与相一致的结果Equals

  • 如果您的编程语言支持运算符重载,并且重载相等运算符对于给定的类型,还必须重写Equals(Object)方法以返回与相等运算符相同的结果。 这有助于确保使用的类库代码Equals(如ArrayListHashtable) 中运作的方式与应用程序代码使用相等运算符的方法一致。

以下准则适用于重写Equals(Object)对于引用类型︰

  • 请考虑重写Equals的类型语义是否基于这一事实的类型表示某些值。

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

  • 不应覆盖Equals上可变的引用类型。 这是因为在重写Equals需要,还可以覆盖GetHashCode方法上, 一节中所述。 这意味着,可变的引用类型的实例的哈希代码可以更改在其生存期内,这可能导致哈希表中的对象会丢失。

以下准则适用于重写Equals(Object)对于值类型︰

  • 如果你正在定义包括一个或多个字段的值类型其值是引用类型,则应重写Equals(Object) Equals(Object)由提供实现ValueType执行逐字节比较的值类型字段是所有的值类型,但它使用反射来执行其字段包括引用类型的值类型的字段的比较。

  • 如果你重写Equals和你的开发语言支持运算符重载,因此您必须重载相等运算符。

  • 应实现IEquatable<T>接口。 调用的强类型化IEquatable<T>.Equals方法可避免装箱obj自变量。

下面的示例演示Point类,并重写Equals方法以提供值是否相等和Point3D派生自的类Point 因为Point重写Object.Equals(Object)来测试值相等性Object.Equals(Object)不调用方法。 但是,Point3D.Equals调用Point.Equals因为Point实现Object.Equals(Object)提供值是否相等的方式。

using System;

class Point
{
   protected int x, y;

   public Point() : this(0, 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) || ! this.GetType().Equals(obj.GetType())) {
         return false;
      }
      else { 
         Point p = (Point) obj; 
         return (x == p.x) && (y == p.y);
      }   
   }

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

    public override string ToString()
    {
        return String.Format("Point({0}, {1})", x, y);
    }
}

sealed class Point3D: Point 
{
   int z;

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

   public override bool Equals(Object obj) 
   {
      Point3D pt3 = obj as Point3D;
      if (pt3 == null)
         return false;
      else
         return base.Equals((Point)obj) && z == pt3.z;
   }

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

   public override String ToString() 
   {
        return String.Format("Point({0}, {1}, {2})", x, y, z);
    }
}

class Example 
{
  public static void Main() 
  {
     Point point2D = new Point(5, 5);
     Point3D point3Da = new Point3D(5, 5, 2);
     Point3D point3Db = new Point3D(5, 5, 2);
     Point3D point3Dc = new Point3D(5, 5, -1);

     Console.WriteLine("{0} = {1}: {2}", 
                       point2D, point3Da, point2D.Equals(point3Da));
     Console.WriteLine("{0} = {1}: {2}", 
                       point2D, point3Db, point2D.Equals(point3Db));        
     Console.WriteLine("{0} = {1}: {2}", 
                       point3Da, point3Db, point3Da.Equals(point3Db));
     Console.WriteLine("{0} = {1}: {2}", 
                       point3Da, point3Dc, point3Da.Equals(point3Dc));
  } 
}
// The example displays the following output:
//       Point(5, 5) = Point(5, 5, 2): False
//       Point(5, 5) = Point(5, 5, 2): False
//       Point(5, 5, 2) = Point(5, 5, 2): True
//       Point(5, 5, 2) = Point(5, 5, -1): False

The Point.Equals method checks to make sure that the obj argument is not null and that it references an instance of the same type as this object. If either check fails, the method returns false.

The Point.Equals method calls the M:System.Object.GetType method to determine whether the run-time types of the two objects are identical. If the method used a check of the form obj is Point in C# or TryCast(obj, Point) in Visual Basic, the check would return true in cases where obj is an instance of a derived class of Point, even though obj and the current instance are not of the same run-time type. Having verified that both objects are of the same type, the method casts obj to type Point and returns the result of comparing the instance fields of the two objects.

In Point3D.Equals, the inherited Point.Equals method, which overrides M:System.Object.Equals(System.Object), is invoked before anything else is done. Because Point3D is a sealed class (NotInheritable in Visual Basic), a check in the form obj is Point in C# or TryCast(obj, Point) in Visual Basic is adequate to ensure that obj is a Point3D object. If it is a Point3D object, it is cast to a Point object and passed to the base class implementation of M:System.Object.Equals(System.Object). Only when the inherited Point.Equals method returns true does the method compare the z instance fields introduced in the derived class.

下面的示例定义Rectangle内部实现作为两个矩形类Point对象。 Rectangle类还将重写Object.Equals(Object)提供的值是否相等。

using System;

class Rectangle 
{
   private 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) {
      // Perform an equality check on two rectangles (Point object pairs).
      if (obj == null || GetType() != obj.GetType()) 
          return false;
      Rectangle r = (Rectangle)obj;
      return a.Equals(r.a) && b.Equals(r.b);
   }

   public override int GetHashCode() {
      return Tuple.Create(a, b).GetHashCode();
   }

    public override String ToString() 
    {
       return String.Format("Rectangle({0}, {1}, {2}, {3})",
                            a.x, a.y, b.x, b.y); 
    }
}

class Point 
{
  internal int x;
  internal 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 Tuple.Create(x, y).GetHashCode();
  }
}

class Example 
{
   public static void Main() 
   {
      Rectangle r1 = new Rectangle(0, 0, 100, 200);
      Rectangle r2 = new Rectangle(0, 0, 100, 200);
      Rectangle r3 = new Rectangle(0, 0, 150, 200);

      Console.WriteLine("{0} = {1}: {2}", r1, r2, r1.Equals(r2));
      Console.WriteLine("{0} = {1}: {2}", r1, r3, r1.Equals(r3));
      Console.WriteLine("{0} = {1}: {2}", r2, r3, r2.Equals(r3));
   }
}
// The example displays the following output:
//    Rectangle(0, 0, 100, 200) = Rectangle(0, 0, 100, 200): True
//    Rectangle(0, 0, 100, 200) = Rectangle(0, 0, 150, 200): False
//    Rectangle(0, 0, 100, 200) = Rectangle(0, 0, 150, 200): False

某些语言中的如 C# 和 Visual Basic 支持运算符重载。 当某个类型重载相等运算符时,它还必须重写Equals(Object)方法以提供相同的功能。 这通常通过编写实现Equals(Object)方面重载的相等运算符,如以下示例所示的方法。

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 Tuple.Create(re, 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);
   }

    public override String ToString()
    {
       return String.Format("({0}, {1})", re, im);
    } 
}

class MyClass 
{
  public static void Main() 
  {
    Complex cmplx1, cmplx2;

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

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

    Console.WriteLine("{0} <> {1}: {2}", cmplx1, cmplx2, cmplx1 != cmplx2);        
    Console.WriteLine("{0} = {1}: {2}", cmplx1, cmplx2, cmplx1.Equals(cmplx2));        

    cmplx2.re = 4.0;

    Console.WriteLine("{0} = {1}: {2}", cmplx1, cmplx2, cmplx1 == cmplx2);        
    Console.WriteLine("{0} = {1}: {2}", cmplx1, cmplx2, cmplx1.Equals(cmplx2));          
  }
}
// The example displays the following output:
//       (4, 1) <> (2, 1): True
//       (4, 1) = (2, 1): False
//       (4, 1) = (4, 1): True
//       (4, 1) = (4, 1): True

Because Complex is a value type, it cannot be derived from. Therefore, the override to M:System.Object.Equals(System.Object) method need not call M:System.Object.GetType to determine the precise run-time type of each object, but can instead use the is operator in C# or the TypeOf operator in Visual Basic to check the type of the obj parameter.

通用 Windows 平台
自 8 起可用
.NET Framework
自 1.1 起可用
可移植类库
可移植 .NET 平台 中受支持
Silverlight
自 2.0 起可用
Windows Phone Silverlight
自 7.0 起可用
Windows Phone
自 8.1 起可用
返回页首
显示: