본문 바로가기
책/Effective C#

Effective C# - Item 25 타입 매개변수로 인스턴스 필드를 만들 필요가 없다면 제네릭 메서드를 정의하라

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

제네릭 클래스를 정의하면 클래스 전체에 대하여 제약 조건을 고려해야한다. 제약 조건의 적용 범위가 넓어지면 넓어질수록 코드를 수정하기가 까다로워진다. 그러므로 제네릭 클래스보다 제네릭 메서드를 사용하는 것이 낫다. 


1. 제네릭 클래스를 사용하는 경우

public static class Utils<T>
{
    public static T Max(T left, T right) =>
        Comparer<T>.Default.Compare(left,right) < 0 ? right : left;
    
    public static T Min(T left, T right) =>
        Comparer<T>.Default.Compare(left,right) > 0 > left : right;
}

제네릭 클래스를 사용하는 경우 타입 매개변수를 명시적으로 지정하여 메서드를 호출해야한다. 이는 컴파일러가 컴파일 타임에 정적으로 타입 검사(static type checking)를 하기 때문이다. 이는 소스 코드를 바이너리 코드로 변환할때 컴파일러가 변수,메서드,클래스등의 타입을 미리 확인하는 것이다.

double d1 = 4;
double d2 = 5;
double max = Utils<double>.Max(d1,d2)

.NET Framework에 포함된 상당히 많은 타입이 이미 Max,Min 메서드를 가지고 있다. 모든 숫자 타입에 대하여 사용할 수 있는 Math.Max(), Math.Min()도 있다. 이 같은 메서드를 사용할 수 있음에도 불구하고 항상 타입 매개변수가 구현한 Comparer<T>를 꺼내서 사용한다. 이 방식도 동작에는 문제가 없지만 매번 타입 매개변수가 IComparer<T>를 구현하는지 런타임에 확인해야하고 그 이후에야 비로소 메서드를 호출해야한다.


2. 클래스내에 제네릭 메서드 구현

public static class Utils
{
    public static T Max(T left, T right) =>
        Comparer<T>.Default.Compare(left,right) < 0 ? right : left;
   
    public static double Max(double left, double right) =>
        Math.Max(left,right);
   
    public static T Min(T left, T right) =>
        Comparer<T>.Default.Compare(left,right) > 0 > left : right;

Utils 클래스는 더 이상 제네릭 클래스가 아니다. 대신 Min,Max에 대하여 여러 개의 오버로딩 메서드를 작성했다. 이처럼 타입을 구체적으로 지정한 메서드는 제네릭 버전보다 효율적으로 동작한다. 그리고 이 메서드를 사용할 때에도 더 이상 타입 매개변수를 명시적으로 지정할 필요가 없다.

double d1 = 4;
double d2 = 5;
double max = Utils.Max(d1,d2);

string code = "code";
string piggy = "piggy";
strimg smax = Utils.Max(code,piggy);

결론

클래스 내에 타입 매개변수로 주어진 타입으로 내부 상태를 유지해야 하는 경우 또는 제네릭 인터페이스를 구현해야 하는 경우에는 제네릭 클래스를 사용하는 것이 좋다. 하지만 위의 두 가지 경우가 아니라면 제네릭 메서드를 사용한 일반 클래스를 만드는 것이 더 좋다.

 

 

 

 

 

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

 

 

 

반응형

댓글