본문 바로가기
C#

[C#] IEqualityComparer<T>, IEqualityComparer, EqualityComparer

by DANEW 2023. 10. 2.

IEqualityComparer<T> 인터페이스

 

IEqualityComparer<T> 인터페이스 (System.Collections.Generic)

개체가 같은지 비교할 수 있는 메서드를 정의합니다.

learn.microsoft.com



IEqualityComparer 인터페이스

 

IEqualityComparer 인터페이스 (System.Collections)

개체가 같은지 비교할 수 있는 메서드를 정의합니다.

learn.microsoft.com

namespace System.Collections
{
    public interface IEqualityComparer
    {
        bool Equals(object x, object y);
        int GetHashCode(object obj);
    }
}
반응형


EqualityComparer<T> 클래스

 

EqualityComparer<T> 클래스 (System.Collections.Generic)

IEqualityComparer<T> 제네릭 인터페이스의 구현에 대한 기본 클래스를 제공합니다.

learn.microsoft.com

namespace System.Collections.Generic
{    
    public abstract class EqualityComparer<T> : IEqualityComparer, IEqualityComparer<T>
    {
        protected EqualityComparer();
       
        public static EqualityComparer<T> Default { get; }
 
        public abstract bool Equals(T x, T y);
        public abstract int GetHashCode(T obj);
    }
}



- 기본 방식 이외의 상등 비교나 해시 계산 구현을 위한 상등 비교자(Equality Comparer)를 만드는데 사용 됨
- 주로 Dictionary 클래스와 Hashtable 클래스에 유용

- 해시테이블 기반 사전들의 요구 사항
 * 해당 키와 같은(상등하는) 키의 존재 여부
 * 해당 키의 정수 해시코드

- 상등 비교자를 작성할 때에는 제네릭, 비제네릭 인터페이스 중 하나, 혹은 둘 다를 구현
- 두개를 다 구현하기 귀찮다면 EqualityComparer 클래스를 상속받아서 한번에 처리

- 커스텀 상등자를 이용한 비교

using System;
using System.Collections.Generic;
 
namespace Practice
{
    class Program
    {
        public static void Main(string[] arg)
        {
            Customer c1 = new Customer("Jaina", "Proudmoore");
            Customer c2 = new Customer("Jaina", "Proudmoore");
 
 
            // 기본적 참조 상등 의미론 적용
            Console.WriteLine(c1 == c2);        // false
            Console.WriteLine(c1.Equals(c2));   // false
 
 
            // Dictionary에서의 상등 비교(키 값 검색)
            var dic1 = new Dictionary<Customer, string>();
            dic1[c1] = "the Archmage";
 
            Console.WriteLine(dic1.ContainsKey(c2));    // false
 
 
            // 커스텀 상등 비교자를 이용한 상등 비교
            var cnec = new CustomerNameEqualityComparer();
            var dic2 = new Dictionary<Customer, string>(cnec);
            dic2[c1] = "the Archmage";
 
            Console.WriteLine(dic2.ContainsKey(c2));    // true
        }
    }
   
    public class Customer
    {
        public string LastName { get; set; }
        public string FirstName { get; set; }
 
        public Customer (string last, string first)
        {
            LastName = last;
            FirstName = first;
        }
    }
 
    public class CustomerNameEqualityComparer : EqualityComparer<Customer>
    {
        public override bool Equals(Customer x, Customer y)
        {
            return (x.LastName == y.LastName) && (x.FirstName == y.FirstName);
        }
 
        public override int GetHashCode(Customer obj)
        {
            return $"{obj.LastName};{obj.FirstName}".GetHashCode();
        }
    }
}


- 위 예에서 고객이 사전에 담겨있을 때, 고객의 FirstName과 LastName이 수정되지 않도록 조치해야 한다고 한다.

  그런 장치가 없다면 고객의 해시코드가 변해서 Dictionary가 오작동 할 수 있다고 한다.

- 책에 나온 내용이 저게 다라서 오작동 하는 정확한 이유를 모르겠는데...
  아마 해시코드를 기반으로한 위치에 자료를 저장해놓는데,
  키 값이 변하면서 해쉬코드도 변해버리면 바뀐 곳으로 접근하고
  그 이전에 저장했던(바뀌기 전의 해쉬코드) 곳으로 접근하지 못하게 되서 그런게 아닐까 싶다.
  공부가 더 필요하다.


EqualityComparer<T>.Defalut 메서드
- static object.Equals 메서드 대신 사용 할 수 있는 범용 상등 비교자를 반환
- 먼저 T가 IEquatable<T>를 구현하는지 점검해서, 구현 한다면 사용하므로 박싱 부담이 없음
- 제네릭 메서드에서 특히 유용

static bool Foo<T>(T x, T y)
{
    return EqualityComparer<T>.Default.Equals(x, y);
}









반응형