Данная статья переведена с помощью средств машинного перевода. Чтобы просмотреть ее на английском языке, установите флажок Английский. Вы также можете просматривать английский текст во всплывающем окне, наводя указатель мыши на переведенный текст.
Перевод
Английский

Метод Object.Equals (Object)

 

Опубликовано: Октябрь 2016

Определяет, равен ли заданный объект текущему объекту.

Пространство имен:   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, person1a и person2, которые имеют одинаковое значение. Также назначает person1a другой переменной объекта person1b. Как показывает результат примера, выходные данные person1a и person1b равны, поскольку они ссылаются на один объект. Тем не менее person1a и person2 не равны, несмотря на то, что они имеют одинаковое значение.

    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 объектов, person1 и person2, который имеет то же значение. Как показывают выходные данные примера, несмотря на то, что две переменные объекта ссылаются на разные объекты, person1 и person2 равны, поскольку они имеют одинаковое значение для частного 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 (см. Поддержка приложений для Магазина Windows и среды выполнения Windows в .NET Framework). Классы в Среда выполнения Windows не наследуют Objectи в настоящее время не использовать Equals(Object)метода. При этом они будут иметь ToString, Equals(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.

Structure

ValueType.Equals

Равенство значений (либо прямое побайтовое сравнение, либо сравнение по полям с использованием средств отражения).

Перечисление

Enum.Equals

Значения должны иметь одинаковый тип перечисления и тем же базовым значением.

Делегат

MulticastDelegate.Equals

Делегаты должен иметь тот же тип с списки вызовов идентичными.

interface

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) метод. В списке x, y, и z обозначают ссылки на объекты, которые не являются null.

  • x.Equals(x)Возвращает true, за исключением случаев, с плавающей запятой. В разделе 60559:2011 ISO/IEC и IEEE, информационных технологий--микропроцессора систем--арифметических операций с плавающей запятой.

  • x.Equals(y)Возвращает то же значение, что y.Equals(x).

  • x.Equals(y)Возвращает true Если оба x и y являются NaN.

  • Если (x.Equals(y) && y.Equals(z)) возвращает true, затем x.Equals(z) возвращает true.

  • Последующие вызовы x.Equals(y) возвращает то же значение, при условии, что объект, который ссылается x и y не изменяются.

  • x.Equals(null) возвращает false.

Реализации Equals не должны выдавать исключения; они должны всегда возвращать значение. Например если objnull, Equals метод должен возвращать false вместо создания ArgumentNullException.

Придерживайтесь следующих правил при переопределении метода Equals(Object):

  • Типы, реализующие IComparable необходимо переопределить Equals(Object).

  • Типы, переопределяющие Equals(Object) необходимо также переопределить GetHashCode; в противном случае хэш-таблицы могут работать неправильно.

  • Следует рассмотреть возможность реализации IEquatable<T> интерфейс для поддержки строго типизированных тесты на равенство. Ваш IEquatable<T>.Equals реализации должен возвращать результаты, которые соответствуют Equals.

  • Если язык программирования поддерживает перегрузку операторов и перегрузка оператора равенства для данного типа, необходимо также переопределить Equals(Object) метод для возврата тот же результат, что и оператор равенства. Это позволяет гарантировать, что код библиотеки классов, использующий Equals (такие как ArrayList и Hashtable) ведет себя таким способом, который согласуется с тем, как оператор равенства, используемый кодом приложения.

Следующие правила применяются к переопределенным 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
Вернуться в начало
Показ: