티스토리 뷰
[Effective C# Item 10] 베이스 클래스가 업그레이드된 경우에만 new 한정자를 사용하라
weekyear 2020. 10. 18. 14:12[Effective C# Item 10]
베이스 클래스가 업그레이드된 경우에만 new 한정자를 사용하라
베이스 클래스에서 virtual로 선언하지 않은 멤버를 재정의하려는 경우에 new 한정자를 사용해서 재정의할 수 있다. 허나 사용할 수 있는 것과 잘 사용하는 것은 전혀 다른 이야기다. 모든 프로그래밍에서 그렇듯 안 될 거 같은 것을 억지로 바꾸려할 경우에는 사용하는 데 있어서 신중해야 한다. 앞의 Item 9의 박싱과 언박싱도 그 예중 하나다.
virtual로 선언되지 않은 메서드를 new 한정자로 억지로 재정의하면 메서드의 동작 방식을 모호하게 만들 우려가 있기 때문이다.
엉? 왜 동작이 다른거야?
MyOtherClass가 MyClass를 상속했다는 사실을 알고 위 코드를 개발자들이 보면 같은 동작을 할 것으로 예상된다. 하지만 다음과 같이 MyOhterClass에서 new 한정자를 이용하여 MagicMethod를 재정의했다면 두 메서드의 호출 결과는 전혀 달라질 것이다.
이렇게 코딩할 경우 개발자들은 혼돈스럽게 된다. 동일한 객체를 상속받는 경우 동일한 메서드는 같은 동작을 할 것이라고 생각하기 때문이다. 사실 new 한정자는 비가상 메서드를 가상 메서드로 만드는 것이 아니라 클래스의 명명 범위(naming scope) 내에 새로운 메서드를 추가하는 역할을 수행한다.
new 한정자를 자제해야 하는 이유
그럼 new 한정자를 사용하지 않기 위해 애초에 가상 메서드로 작성하면 될 것 아니냐라는 반문이 있을 수도 있다. 하지만 가상 메서드의 경우에는 클래스의 가능성을 제약한다기 보다는 클래스 활용 방법에 대한 가이드라인을 제시하는 느낌으로 사용하기 때문에 첫 개발자가 해당 메서드의 다형성을 고려하지 않고 가상 메서드로 작성하지 않았을 수 있다. 이럴 경우 new 한정자를 사용하는 것이다.
new 한정자를 활용해도 좋은 경우는 베이스 클래스에서 이미 사용하고 있는 메서드를 재정의하여 완전히 새로운 베이스 클래스를 만들어야 하는 경우 정도 밖에 없다.
new 한정자가 필요한 경우
new 한정자가 필요한 시나리오를 생각해보자. 외부에서 구매한 라이브러리에 포함된 BaseWidget이라는 클래스를 상속하여 다음과 같이 MyWidget을 정의했다고 가정하자.
많은 클라이언트들이 MyWidget을 잘 사용하고 있는데 BaseWidget의 개발자들이 대뜸 NormalizeValues()라는 같은 이름의 메서드를 새로 추가해버렸다. 메서드의 이름이 겹쳐버린 것이다.
이 문제를 해결하기 위해서는 두 가지 방법이 있다.
우선, MyWidget 클래스에 정의한 NormalizeValues() 메서드의 이름을 NormalizeAllValues() 등 다른 이름으로 교체하는 것이다.
또 다른 방법은 new 한정자를 사용하는 방법이다. 이때, new 한정자를 사용하는 이유는 기존 MyWidget의 클라이언트들이 메서드 이름의 변경으로 인한 헷갈림을 방지하기 위해서다.
이런 경우에 new 한정자를 사용할 수 있지만 이 예시에서도 new 한정자를 사용하는데 있어서 신중해야 한다. 시간이 지남에 따라 BaseWidget의 NormalizeValues() 메서드를 사용하는 경우도 늘어나면 이름은 같은데 서로 다르게 동작하는 메서드에 여러 사용자들이 혼동을 빚을 수 있기 때문이다. 장기적으로 보면 지금 잠깐의 혼동으로 끝내는 것이 더 나을 수 있다는 말이다.
new 한정자를 사용할 때는 각별한 주의가 필요하다. 재정의가 예정되어 있지 멤버를 억지로 재정의하려는 경우이니 많은 사람들이 오해를 할 수 있기 때문이다.
따라서 베이스 클래스가 업그레이드되어 메서드의 이름이 충돌하는 경우는 매우 특별한 경우라 new 한정자를 고려해볼 수는 있으나 이 경우에도 신중하게 사용되어져야 하고 이 이외에는 절대로 new 한정자를 사용해서는 안 된다!!
공부하면 할 수록 그동안 코딩하면서 허투루 넘어간 부분이 많다는 것을 깨닫는다.
new 한정자를 몇 번 조우한 적이 있지만 별 다른 생각하지 않고 넘어간 것이 기억난다.
이제 new 한정자를 만났을 때 지금은 new 한정자를 써도 괜찮은가 의문을 던져볼 수 있게 되었다.
참조 - Effective C# <강력한 C# 코드를 구현하는 50가지 전략과 기법, 이펙티브>, 빌 와그너, 김명신, 한빛미디어
'Programming > Effective C#' 카테고리의 다른 글
[Effective C# Item 12] 할당 구문보다 멤버 초기화 구문이 좋다 (0) | 2020.10.18 |
---|---|
[Effective C# Item 11] .NET 리소스 관리에 대한 이해 (0) | 2020.10.18 |
[Effective C# Item 9] 박싱과 언박싱을 최소화하라 (0) | 2020.10.18 |
[Effective C# Item 8] 이벤트 호출 시에는 null 조건 연산자(?.)를 사용하라 (0) | 2020.10.18 |
[Effective C# Item 7] 델리게이트를 이용하여 콜백을 표현하라 (0) | 2020.10.18 |