다음을 통해 공유


Equals 메서드 구현

같음 연산자(==) 구현에 대한 관련 내용은 Equals 및 같음 연산자(==) 구현 지침을 참조하십시오.

  • 형식이 해시 테이블에서 올바르게 동작하도록 하려면 GetHashCode 메서드를 재정의합니다.

  • Equals 메서드 구현에서 예외를 throw하지 않습니다. 대신, null 인수에 대해 false를 반환합니다.

  • 다음과 같이 Object.Equals 메서드에 정의된 계약을 따릅니다.

    • x.Equals(x)는 true를 반환합니다.

    • x.Equals(y)는 y.Equals(x)와 같은 값을 반환합니다.

    • (x.Equals(y) && y.Equals(z))는 x.Equals(z)가 true를 반환하는 경우에만 true를 반환합니다.

    • x와 y로 참조되는 개체가 수정되지 않았으면 x.Equals(y)의 후속 호출에서는 같은 값을 반환합니다.

    • x.Equals(null)는 false를 반환합니다.

  • 일부 종류의 개체의 경우에는 참조 일치 대신 값 일치에 대한 Equals 테스트를 수행하는 것이 좋습니다. 이렇게 Equals를 구현하는 경우, 두 개의 개체가 같은 인스턴스는 아니라도 두 개체에 같은 값이 있으면 true가 반환됩니다. 개체의 값을 구성하는 항목에 대한 정의는 형식 구현자에 따라 다르지만 대개는 개체의 인스턴스 변수에 저장되는 일부 또는 모든 데이터입니다. 예를 들어, 문자열 값은 문자열에 포함된 문자를 기준으로 하며, String 클래스의 Equals 메서드는 정확히 동일한 문자가 동일한 순서로 들어 있는 두 개의 문자열 인스턴스에 대해 true를 반환합니다.

  • 기본 클래스의 Equals 메서드를 통해 값 일치가 제공되는 경우 파생 클래스에서 재정의된 Equals는 상속 구현된 Equals를 호출해야 합니다.

  • 연산자 오버로드를 지원하는 언어로 프로그래밍하고 있으며 지정된 형식에 대해 같음 연산자(==)를 오버로드하기로 선택하는 경우, 해당 형식은 Equals 메서드를 재정의해야 합니다. 이렇게 구현된 Equals 메서드는 같음 연산자와 동일한 결과를 반환해야 합니다. 이 지침에 따르면 Equals를 사용하는 ArrayListHashtable 등의 클래스 라이브러리 코드는 응용 프로그램 코드에서 같음 연산자가 사용되는 방식과 같은 방식으로 작동합니다.

  • 값 형식을 구현하는 경우에는 Equals 메서드를 재정의하여 ValueType의 기본 구현된 Equals 메서드보다 향상된 성능을 얻는 것이 좋습니다. Equals를 재정의하는 경우 해당 언어에서 연산자 오버로드를 지원하면 값 형식에 대해 같음 연산자를 오버로드해야 합니다.

  • 참조 형식을 구현할 때 Point, String, BigNumber 등의 기본 형식처럼 보이는 형식인 경우 참조 형식에서 Equals 메서드를 재정의할 것인지 고려해야 합니다. 대부분의 참조 형식은 Equals를 재정의한 경우에도 같음 연산자를 재정의해서는 안 됩니다. 그러나 복잡한 숫자 형식 같이 값 의미를 가지도록 된 참조 형식을 구현하는 경우에는 같음 연산자를 재정의해야 합니다.

  • 지정된 형식에 대해 IComparable 인터페이스를 구현하는 경우 해당 형식에 대해 Equals를 재정의해야 합니다.

예제

다음 코드 예제에서는 Equals 메서드를 구현하고, 호출을 재정의하며, 오버로드하는 방법을 보여 줍니다.

Equals 메서드 구현

다음 코드 예제에서는 기본 구현된 Equals 메서드를 두 번 호출합니다.

Imports System
Class SampleClass   
   Public Shared Sub Main()
      Dim obj1 As New System.Object()
      Dim obj2 As New System.Object()
      Console.WriteLine(obj1.Equals(obj2))
      obj1 = obj2
      Console.WriteLine(obj1.Equals(obj2))
   End Sub
End Class
using System;
class SampleClass 
{
   public static void Main() 
   {
      Object obj1 = new Object();
      Object obj2 = new Object();
      Console.WriteLine(obj1.Equals(obj2));
      obj1 = obj2; 
      Console.WriteLine(obj1.Equals(obj2)); 
   }
}

이 코드는 다음과 같이 출력됩니다.

False
True

Equals 메서드 재정의

다음 코드 예제에서는 Equals 메서드를 재정의하여 값 일치를 제공하는 Point 클래스와 Point에서 파생된 Point3D 클래스를 보여 줍니다. Point 클래스는 값 일치를 사용하는 상속 체인에서 처음으로 Equals를 재정의하므로, Object에서 상속되어 참조 일치를 검사하는 기본 클래스의 Equals 메서드는 호출되지 않습니다. 그러나 Point는 값 일치를 제공하는 방식으로 Equals를 구현하기 때문에 Point3D.Equals는 Point.Equals를 호출합니다.

Namespace Examples.DesignGuidelines.EqualsImplementation

Public Class Point  
   Protected x As Integer
   Protected y As Integer

   Public Sub New (xValue As Integer, yValue As Integer)
    Me.x = xValue
    Me.y = yValue
   End Sub

   Public Overrides Overloads Function Equals(obj As Object) As Boolean

      If obj Is Nothing OrElse Not Me.GetType() Is obj.GetType() Then
         Return False
      End If

      Dim p As Point = CType(obj, Point)
      Return Me.x = p.x And Me.y = p.y
   End Function 

   Public Overrides Function GetHashCode() As Integer
      Return x Xor y
   End Function 
End Class 

Public Class Point3D
   Inherits Point
   Private z As Integer

   Public Sub New (xValue As Integer, yValue As Integer, zValue As Integer)
      MyBase.New(xValue, yValue)
      Me.z = zValue
   End Sub

   Public Overrides Overloads Function Equals(obj As Object) As Boolean
      Return MyBase.Equals(obj) And z = CType(obj, Point3D).z
   End Function 

   Public Overrides Function GetHashCode() As Integer
      Return MyBase.GetHashCode() Xor z
   End Function 
End Class 

End Namespace

using System;

namespace Examples.DesignGuidelines.EqualsImplementation
{
class Point: object 
{
   protected int x, y;

   public Point(int xValue, int yValue)
   {
        x = xValue;
        y = yValue;
   }
   public override bool Equals(Object obj) 
   {
      // Check for null values 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 xValue, int yValue, int zValue) : base(xValue, yValue)
   {
        z = zValue;
   }
   public override bool Equals(Object obj) 
   {
      return base.Equals(obj) && z == ((Point3D)obj).z;
   }
   public override int GetHashCode() 
   {
      return base.GetHashCode() ^ z;
   }
}
}
using namespace System;

namespace Examples { namespace DesignGuidelines { namespace EqualsImplementation
{
    ref class Point : Object
    {
    protected:
        int x, y;

    public:
        Point(int xValue, int yValue)
        {
            x = xValue;
            y = yValue;
        }

        virtual bool Equals(Object^ obj) override
        {
            // Check for null values and compare run-time types.
            if (obj == nullptr || GetType() != obj->GetType())
            {
                return false;
            }

            Point^ p = (Point^)obj;

            return (x == p->x) && (y == p->y);
       }

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

    ref class Point3D : Point
    {
    private:
        int z;

    public:
        Point3D(int xValue, int yValue, int zValue) : Point(xValue, yValue)
        {
            z = zValue;
        }

        virtual bool Equals(Object^ obj) override
        {
            return Point::Equals(obj) && z == ((Point3D^)obj)->z;
        }

        virtual int GetHashCode() override
        {
            return Point::GetHashCode() ^ z;
        }
    };
}}}

Point.Equals 메서드는 obj 인수가 null이 아닌지 검사하고 이 인수가 해당 개체와 같은 형식의 인스턴스를 참조하는지 검사합니다. 두 검사 중 하나에 실패하면 이 메서드는 false를 반환합니다. Equals 메서드는 GetType 메서드를 사용하여 두 개체의 런타임 형식이 동일한지 여부를 확인합니다. typeof(Visual Basic의 경우 TypeOf)는 정적 형식을 반환하므로 여기에서는 사용하지 않습니다. 메서드가 obj is Point 형식의 검사를 대신 사용한 경우, obj가 Point에서 파생된 클래스의 인스턴스이면 obj와 현재 인스턴스의 런타임 형식이 동일하지 않아도 검사에서 true가 반환됩니다. 두 개체가 동일한 형식인지 확인한 후 이 메서드는 obj를 Point 형식으로 캐스팅하고 두 개체의 인스턴스 변수를 비교한 결과를 반환합니다.

Point3D.Equals에서 상속된 Equals 메서드는 다른 작업이 수행되기 전에 호출됩니다. 상속된 Equals 메서드는 obj가 null이 아닌지 확인하고 obj가 해당 개체와 같은 클래스의 인스턴스인지 확인한 다음 상속된 인스턴스 변수가 일치하는지 확인합니다. 이 메서드는 상속된 Equalstrue를 반환하는 경우에만 파생 클래스에서 사용하는 인스턴스 변수를 비교합니다. 특히, obj가 Point3D 형식이거나 Point3D에서 파생된 클래스인 것으로 확인되지 않았으면 Point3D로의 캐스팅은 실행되지 않습니다.

Equals 메서드를 사용하여 인스턴스 변수 비교

앞의 예제에서 같음 연산자(==)는 각 인스턴스 변수를 비교하는 데 사용됩니다. 일부 경우에는 다음 코드 예제에서와 같이 Equals 구현에서 Equals 메서드를 사용하여 인스턴스 변수를 비교하는 것이 적절합니다.

Imports System

Class Rectangle
   Private a, b As Point
   
   Public Overrides Overloads Function Equals(obj As [Object]) As Boolean
      If obj Is Nothing Or Not Me.GetType() Is obj.GetType() Then
         Return False
      End If
      Dim r As Rectangle = CType(obj, Rectangle)
      ' Use Equals to compare instance variables.
      Return Me.a.Equals(r.a) And Me.b.Equals(r.b)
   End Function 
   
   Public Overrides Function GetHashCode() As Integer
      Return a.GetHashCode() ^ b.GetHashCode()
   End Function 
End Class 
using System;
class Rectangle 
{
   Point a, b;
   public override bool Equals(Object obj) 
   {
      if (obj == null || GetType() != obj.GetType()) return false;
      Rectangle r = (Rectangle)obj;
      // Use Equals to compare instance variables.
      return a.Equals(r.a) && b.Equals(r.b);
   }
   public override int GetHashCode() 
   {
      return a.GetHashCode() ^ b.GetHashCode();
   }
}

같음 연산자(==) 및 Equals 메서드 오버로드

C# 등의 일부 프로그래밍 언어에서는 연산자 오버로드가 지원됩니다. 한 형식에서 같음 연산자(==)를 오버로드하면 해당 형식은 Equals 메서드도 재정의하여 같은 기능을 제공해야 합니다. 대개는 다음 예제에서와 같이 오버로드된 같음 연산자(==)에 따라 Equals 메서드를 작성하면 됩니다.

public struct Complex 
{
   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);
   }
}

Complex는 C# struct(값 형식)이기 때문에 Complex에서 파생되는 클래스는 없습니다. 따라서 Equals 메서드가 각 개체의 GetType 결과를 비교하지 않아도 됩니다. 대신 이 메서드는 is 연산자를 사용하여 obj 매개 변수의 형식을 검사합니다.

Portions Copyright 2005 Microsoft Corporation. All rights reserved.

Portions Copyright Addison-Wesley Corporation. All rights reserved.

디자인 지침에 자세한 내용은 참조를 "Framework 디자인 지침: 규칙, 숙어, 및 재사용에 대 한 패턴입니다.NET 라이브러리"도 서 Krzysztof Cwalina와 Brad Abrams, 게시 Addison-wesley, 2005.

참고 항목

기타 리소스

클래스 라이브러리 개발을 위한 디자인 지침