방프리
21.03.30 Chapter3. 제네릭 활용 (Item 26) 본문
Item 26 : 제네릭 인터페이스와 논제네릭 인터페이스를 함께 구현하라
제네릭 타입은 C# 초기부터 있던 기능이 아니기 때문에 예전버전까지 호환해야한다면 이를 고려해야 한다.
세 가지 요소(클래스와 인터페이스, public 속성, Serialize)를 모두 지원해주어야 한다.
하단의 코드는 논제네릭 방식으로 구현된 (레거시 코드) Name 클래스이다.
public class Name : IComparable<Name>, IEquatable<Name>
{
public string First { get; set; }
public string Last { get; set; }
public string Middle { get; set; }
public int CompareTo(Name other)
{
if (Object.ReferenceEquals(this, other))
return 0;
if (Object.ReferenceEquals(other, null))
return 1;
int rVal = Comparer<string>.Default.Compare(Last, other.Last);
if (rVal != 0)
return rVal;
rVal = Comparer<string>.Default.Compare(First, other.First);
if (rVal != 0)
return rVal;
return Comparer<string>.Default.Compare(Middle, other.Middle);
}
public bool Eqauls(Name other)
{
if (ReferenceEquals(this, other))
return true;
if (ReferenceEquals(other, null))
return false;
return Last == other.Last &&
First == other.First &&
Middle == other.Middle;
}
}
제네릭 클래스가 된다면 상호 비교나 값의 동일성 체크 전에 타입의 동일성 체크가 먼저 이루어져야 하는데,
해당 메서드는 제네릭 메서드로 정의해야한다.
public static bool CheckEquality<T>(T left, T right)
where T : IEquatable<T>
{
if (left == null)
return right == null;
return left.Equals(right);
}
논제네릭 클래스들을 위해서도 따로 타입 동일성 비교 함수를 구현해주어야 한다.
public override bool Equals(object obj)
{
if (obj.GetType() == typeof(Name))
return this.Equals(obj as Name);
else
return false;
}
Equals를 재정의 했다면, GetHashCode도 재정의하자
public override int GetHashCode()
{
int hashCode = 0;
if (Last != null)
hashCode ^= Last.GetHashCode();
if (First != null)
hashCode ^= First.GetHashCode();
if (Middle != null)
hashCode ^= Middle.GetHashCode();
return hashCode;
}
IEquality<T>를 구현하였다면, operator==와 operator !=도 함께 구현되어야 한다.
public static bool operator ==(Name left, Name 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);
}
동등성 비교를 하였으니 이제 선후 관계 비교를 구현해보자.
public class Name : IComparable<Name>, IEquatable<Name>, IComparable
{
int IComparable.CompareTo(object obj)
{
if (obj.GetType() != typeof(Name))
throw new ArgumentException("Argument is not a Name object");
return this.CompareTo(obj as Name);
}
}
IComparable같은 논제네릭 타입의 인터페이스를 구현할 때 명시적인 인터페이스 구현 방식을 사용해야 한다.
다음의 코드들은 논제네릭방식의 메서드 구현이다.
public static bool operator <(Name left, Name right)
{
if (left == null)
return right != null;
return left.CompareTo(right) < 0;
}
public static bool operator >(Name left, Name right)
{
if (left == null)
return false;
return left.CompareTo(right) < 0;
}
선후 관계와 동일성 관계를 함께 정의하는 '<='와 '>=' 연산자도 구현해야 한다.
public static bool operator <=(Name left, Name right)
{
if (left == null)
return true;
return left.CompareTo(right) <= 0;
}
public static bool operator >=(Name left, Name right)
{
if (left == null)
return right == null;
return left.CompareTo(right) >= 0;
}
위의 메서드 구현방식을 참고하여 레거시 코드와 같이 사용되는 제네릭 클래스를 구현할 때 포함되는 인터페이스에
따라 메서드를 명시적으로 구현해주어야 한다.
'C# > Effective C#' 카테고리의 다른 글
21.03.31 Chapter3. 제네릭 활용 (Item 28) (0) | 2021.03.31 |
---|---|
21.03.30 Chapter3. 제네릭 활용 (Item 27) (0) | 2021.03.30 |
21.03.28 Chapter3. 제네릭 활용 (Item 25) (0) | 2021.03.28 |
21.03.27 Chapter3. 제네릭 활용 (Item 24) (0) | 2021.03.27 |
21.03.14 Chapter3. 제네릭 활용 (Item 23) (0) | 2021.03.14 |
Comments