본문 바로가기
카테고리 없음

[Effective C#] Item 35 확장 메서는 절대 오버로드 하지 마라

by 코모's 2023. 2. 1.
반응형

확장 메서드는 설계 의도를 드러내는 방법으로는 썩 훌륭하지 않다. 확장 메서드를 사용하는 대부분의 경우가 기존에 개발된 타입을 개선하기 위해서이지 타입의 본질적인 동작 방식을 변경하기 위해서는 아니기 때문이다.

 

왜 확장 메서드로 타입을 확장해서는 안 되는가?

확장 메서드를 이용하여 인터페이스에 대한 기본 구현체를 제공하는 것이 괜찮은 방법인 것은ㅇ 분명하지만 타입을 확장하기 위한 용도로 사용하는 것은 적절하지 않다.

확장 메서드를 과도하게 사용하거나 잘못 사용하면 메서드 충돌로 인해 유지보수 비용이 급격하게 증가하는 곤경에 처할 수 있기 때문이다.

 

예시) Person 클래스

public sealed class Person
{
	public string FirstName
    {
    	get; set;
    }
    
    public string LastName
    {
    	get; set;
    }
}

 

Person 객체의 FirstName과 LastName을 화면에 출력하기 위해서 확장 메서드를 작성

//좋지않은 시작
//확장 메서드를 이용하여 클래스를 확장함

namespace ConsoleExtemsions
{
	public static class ConsoleReport
    {
    	public static string Format(this Person target) =>
        	target.FirstName + "." + target.LastName;
    }
}


//확장 메서드 사용
using ConsoleExtensions;

Person person = new Person{
	FirstName = "cosmoss",
    LastName = "black"
};

Consel.WriteLine(person.Format());

 

확장 메서드 추가 (XML 파일 출력용 Format() 메서드)

namesapce XmlExtension
{
	public stataic class XmlReport
    {
    	public stataic string Format(this Person target)
        {
        	//생략
        }
    }
}

위 두 코드는 같은 메서드의 이름을 가지고 있고 다른 네임스페이스를 가지고있다.

이런식으로 코드를 작성하면 개발자가 실수로 네임스페이스를 잘못 참조하게 되면 동작 방식이 바뀌어 버린다.

혹은 확장 메서드가 포함된 네임스페이스를 참조하는 것을잊어버리면 컴파일조차 되지 않는다.

네임스페이스를 기반으로 어떤 메서드를 호출할지를 결정하는 방식은 그 구조가 너무 허약하다.

 

또한 앞서 구현한 새로운 기능은 사실 타입의 기능을 확장하는 것으로는 보기 힘들다.

Person 객체를 XML이나 콘솔로 출력하는 기능은 Person 타입의 자체 기능이라기 보다는 외부에서 Person객체를 사용하는 기능이기 때문이다.

 

따라서, 다음과같이 두 메서드를 가능한 동일 클래스 내에 서로다른 이름을 가진 메서드로 작성하는 것이 좋다.

 

public static class PersonReports
{
	public stataic stringFormatAsText(Person target) =>
    	target.FirstAnme + "." + target.LastName;
        
    public static string FormatAsXml(Person target) =>
    	//생략
}

 

이제 Person 타입의 사용자는 특별한 혼동 없이 두 메서드를 모두 사용할 수 있다. 동일한 원형의 메서드를 네임 스페이스의 이름만 달리하여 작성했을 때의 모호함은 사라졌다.

 

결론 

특정 타입에 대해 동작하는 확장 메서드는 하나의 세트로 간주해야한다.

확장메서드를 여러 네임스페이스에 걸쳐 오버로드 해서는 안된다.

동일한 원형의 확장 메서드를 여러개 만들어야 할 경우라도 절대 그렇게 해서는 안된다.

대신 메서드의 이름을 달리하고 정적 메서드로 작성하는 것을 고려하기 바란다.

그래야만 컴파일러가 using 문자을 기반으로 오버로드된 메서드 중 하나를 선택하는 이상한 상황이 버러지지 않는다.

 

 

참조 - Effective C# <강력한 C# 코드를 구현하는 50가지 전략과 기법, 이펙티브>, 빌 와그너, 김명신, 한빛미디어

반응형