제네릭 클래스나 제네릭 메서드를 작성할 때는 사용자가 가능한 안전하고 혼랍스럽지 않도록 작성해야 한다. 특히 오버로드된 메서드가 여러 개인 경우 컴파일러가 이 중 하나를 어떻게 선택하는지 정확히 알고 있어야 한다. 그리고 사용자가 명시적으로 타입을 설정한 일반 메서드보다 제네릭 메서드가 우선적으로 선택되는 경우에 대해서도 명확히 이해하고 있어야 한다.
public class MyBase
{
}
public interface IMessageWriter
{
void WriteMessage();
}
public class MyDerived : MyBase, IMessageWriter
{
void IMessageWriter.WriteMessage() =>
Conosle.WriteLine("Inside MyDerived.WriteMessage");
}
static void WriteMessage(MyBase b)
{
Console.WriteLine("Inside AnotherType.WriteMessage(MyBase)");
}
static void WriteMessage<T>(T obj)
{
Console.Write("Inside WriteMessage<T>(T): ");
Console.WriteLine(obj.ToString());
}
MyDerived d = new MyDerived();
MyBase를 상속한 MyDerived클래스는 WriteMessage(base b)보다 WriteMessage<T>(T obj)가 더 정확히 일치한다. 왜냐하면 제네릭 메서드의 타입 매개변수인 T를 MyDerived로 대체하면 컴파일러 입장에서는 요청한 메서드와 정확히 일치하는 메서드를 찾을 수 있기 때문에다. 반면 WriteMessage(MyBase b)의 경우는 암시적 형변환이 필요하다. MyDerived가 MyBase로 형변환되어야 한다.
Console.WriteLine("Calling Program.WriteMessage");
WriteMessage(d);
출력 결과
Calling Program.WriteMessage
Inside WriteMessage<T>(T): baek2.MyDerived
제네릭 메서드가 있는 경우 요청된 메서드의 원형과 정확히 일치하는 메서드를 생성한 것이기 때문에 베이스 클래스 타입의 매개변수를 취하는 메서드보다 우선적으로 선택된다.
결론
제네릭 메서드의 타입 매개변수로 특정 타입이 주어질 경우 그에 부합하도록 제네릭 특화(Generic Specialization)를 수행하기로 결정했다면 해당 타입뿐 아니라 이 타입을 상속한 모든 파생 타입에 대해서도 특화를 수행해야 한다. 인터페이스에 대해 특화를 수행하기로 결정했다면 이 인터페이스르 구현하고 있는 모든 타입에 대해서도 특화를 수행하도록한다.
본 게시글은 Effective C#을 읽고 정리하였습니다.
'책 > Effective C#' 카테고리의 다른 글
Effective C# - Item 26 제네릭 인터페이스와 논제네릭 인터페이스를 함께 구현하라 (0) | 2023.12.20 |
---|---|
Effective C# - Item 25 타입 매개변수로 인스턴스 필드를 만들 필요가 없다면 제네릭 메서드를 정의하라 (0) | 2023.12.18 |
Effective C# - Item23 타입 매개변수에 대해 메서드 제약 조건을 설정하려면 델리게이트를 활용하라 (0) | 2023.12.15 |
Effective C# - Item 22 공변성과 반공변성을 지원하라 (0) | 2023.12.14 |
Effective C# - Item 21 타입 매개 변수가 IDisposable을 구현한 경우를 대비하여 제네릭 클래스를 작성하라 (0) | 2023.12.10 |
댓글