본문 바로가기
책/Effective C#

Effective C# - Item 26 제네릭 인터페이스와 논제네릭 인터페이스를 함께 구현하라

by 코딩하는 돼징 2023. 12. 20.
반응형

C#에 제네릭이 포함되기 이전에 개발됐던 코드를 무시할 수 있으면 좋겠지만 이전 코드를 무시하기가 어렵다. 새로운 라이브러리를 개발할 때 제네릭 타입뿐 아니라 고전적인 방식도 함께 지원한다면 라이브러리의 활용도를 좀 더 높일 수 있다.

 

만약 제네릭 타입이 아닌 방식도 지원한다면 (1) 클래스와 인터페이스 (2) public 속성 (3) serialize 대상이 되는 요소 세가지에 대해서 논제네릭 non-genric방식을 지원해야 한다. 물론 대부분의 경우 논제네릭 인터페이스를 추가하는 작업은 적절한 원형의 메서드를 추가하는 수준에서 간단히 해결된다. 아닌 경우는 서로간의 상속간계에 속해있을 경우에 발생한다.


01 System.Object이용

앞서 정의한 Name타입으로 CheckEquality를 호출하면 IEquatable<Name>.Equals()를 호출할 것같지만 실제로는 System.Object.Equals()를 호출하게 된다.

public static bool CheckEquality(object left, object right)
{
    if(left == null)
        return right == null;
    return left.Equals(right);
}

System.Object.Equals()는 Object타입을 취하지만 IEqualtable<T>.Equals()는 T타입을 매개변수로 취하기 때문이다.


02 Generic 이용 

제네릭 메서드로 제네릭 제약 조건으로 IEqutable<T>를 사용한다.

public static bool CheckEquality<T>(T left, T right) where T : IEquatable<T>
{
    if(left == null)
        return right == null;
    return left.Equals(right);
}

외부에서 제공 받은 라이브러리나 .NET BCL에 포함된 타입에 임의로 CheckEquality()메서드를 추가할 수 없으므로 논제네릭 버전의 Equals메서드 내에서 IEqutable<T>.Equals()메서드를 호출해야 한다.


04 non-Generic

매개변수로 object obj를 받아 형변환 후 특정 타입('Name')에 대한 비교를 수행한다. 이 방식은 타입에 특화된 구체적인 비교를 수행하고 있으므로 논제네릭 방식이다.

public override bool Equals(object obj)
{
    if(obj.GetType() == typeof(Name))
        return this.Equals(obj as Name);
    else
        return false;
}

Equals를 재정의 했다면 다음으로 GetHasCode도 재정의해야한다.

GetHashCode와 Equals 메서드 간의 관계는 해시 기반의 컬렉션에서 중요한 역할을 한다. 해시 기반의 컬렉션은 빠른 검색을 위해 해시 코드를 사용하며 동일한 해시 코드를 가진 객체끼리만 Equals 메서드를 호출하여 동등성을 확인한다.
기본적으로 Object 클래스에서 상속받은 GetHashCode는 객체의 메모리 주소를 기반으로 한 해시 코드를 반환한다. 만약 두 객체가 Equals에 동등하다면 반드시 같은 해시 코드를 반환해야 한다. 따라서 클래스에서 Equals 메서드를 재정의한 경우, GetHashCode도 적절히 재정의해주어야 한다.


IEquality<T>를 구현했다면 operator ==와 operator !=도 함께 구현해야 한다.

public static bool operator ==(MyClass left, MyClass right)
{
	if (left == null)
		return right == null;
	return left.Equals(right);
}

public static bool operator !=(Name left, Name right)
{
	if (left == null)
		return right != null;
	return !left.Equals(right);
}

결론

예전에 개발된 코드와 함께 사용해야 한다면 반드시 논제네릭 인터페이스를 구현해야 한다. 그리고 구현할 때 반드시 명시적인 방법으로 구현하는 것이 좋다.

 

 

 

 

본 게시글은 Effective C#을 읽고 정리하였습니다.

 

반응형

댓글