베이스 클래스에서 virtual로 선언하지 않은 멤버를 재정의하려는 경우 new 한정자를 사용 할 수 있습니다.
하지만 사용할 수 있다고 해서 new 한정자는 비가상 메서드를 가상 메서드로 만드는 것이 아니라 클래스이 명명 범위 내에 새로운 메서드를 추가하는 역활을 수행합니다.
# override와 new 한정자의 차이
ovrerride로 정의된 가상 메서드를 사용하는 경우는 다음과 같은 결과를 가집니다.
public class BaseClass { public virtual void Func() { Console.WriteLine("MyClass"); } } public class DerivedClass : BaseClass { public override void Func() { Console.WriteLine("DerivedClass"); } } // override를 사용한 가상 메서드 BaseClass cl = new BaseClass(); BaseClass cl2 = new DerivedClass(); cl.Func(); // MyClass 출력 cl2.Func(); // DerivedClass 출력
new 한정자를 이용하는 경우 다음과 같은 결과를 가집니다
public class BaseClass { public void Func() { Console.WriteLine("MyClass"); } } public class DerivedClass : BaseClass { new public void Func() { Console.WriteLine("DerivedClass"); } } // new 한정자를 사용한 비가상 메서드 BaseClass cl = new BaseClass(); BaseClass cl2 = new DerivedClass(); cl.Func(); // MyClass 출력 cl2.Func(); // DerivedClass 출력 DerivedClass dcl = cl2 as DerivedClass; dcl.Func(); // DerivedClass 출력
비가상 메서드는 정적으로 바인딩되므로 런타임에서 파생 클래스에서 새롭게 정의하고 있는 메서드가 있는지 찾지 않습니다.
반면, 가상 메서드는 동적으로 바인딩 되므로 런타임에 객체의 타입이 무엇이냐에 따라 그에 부합하는 메서드를 호출합니다.
가상메서드와 비가상 메서드를 재정의하는 new 한정자의 기능을 제대로 파악하고 사용해야 하며, new 한정자를 사용하지 않기 위해 모든 메서드를 가상메서드로 변경하는 것은 좋지 않습니다.
설계자가 특정 메서드를 가상으로 선언한다는 것은 파생 클래스에서 이 가상 메서드의 구현부를 변경할 것임을 예상하고 있으며, 파생 클래스에서 가상 메서드의 동작 방식을 변경할지라도 아무런 문제 없이 수행될 것임을 보장하는 것입니다. 따라서 어떤 메서드나 속성이 무엇인지를 우선 생각해보고 반드시 다형성이 필요한 경우에만 가상 메서드를 사용해야 합니다.
# new 한정자를 활용하는 경우
new 한정자를 활용해도 좋은 경우는 베이스 클래스에서 이미 사용하고 있는 메서드를 재정의하여 완전히 새로운 베이스 클래스를 만들어야 하는 경우 정도입니다.
이미 널리 사용되고 있는 메서드가 있어서 이를 사용하는 코드를 일일이 찾아서 수정하기 어렵거나, 외부 어셈블리에서 이 메서드를 사용하고 있어서 코드를 수정할 수 없는 경우라면 new 한정자를 사용해 볼 만합니다.
public class MyWidget : BaseWidget { public void NormalizeValues() { // 세부 내용 } }
예를 들어, BaseWidget이라는 클래스를 상속하여 다음과 같이 MyWidget을 정의한 경우가 있고, 많은 사람들이 MyWidget 클래스를 사용 중인 상황에서 BaseWidget에 새로운 버전이 출시되었습니다.
이 때, BaseWidget에 NormalizeValues()라는 새로운 메서드가 추가된다면 빌드가 실패되는 결과가 발생할 것입니다.
이 문제를 해결하기 위해서 두가지 방법이 있다. MyWidget의 메서드 이름을 변경하거나, new 한정자를 사용하는 방법이 있습니다.
앞에서와 같은 상황에서 new 한정자를 이용하면 기존 메서드명을 그대로 사용할 수 있습니다. 하지만, new 한정자를 사용할 때는 각별히 주의해야 합니다.
코드를 모두 수정할 수 있다면 장기적으로 봤을 때는 메서드의 이름을 변경하는 것이 좋습니다. 왜냐하면, BaseWidget의 NormalizeValues()메서드와 같은 이름으로 다르게 동작하는 메서드 존재로 혼동이 올 수도 있기 때문입니다.
여러 상황을 고려하여 신중하게 new 한정자를 사용하는 것을 권합니다.
참 고 : Effective C#
'책 > Effective C#' 카테고리의 다른 글
Item 12. 할당 구문보다 멤버 초기화 구문이 좋다. (0) | 2019.04.17 |
---|---|
Item 11. .NET 리소스 관리에 대한 이해 (0) | 2019.04.17 |
Item 9. 박싱과 언박싱을 최소화하라. (0) | 2019.04.05 |
Item 8. 이벤트 호출 시에는 null 조건 연산자를 사용하라. (0) | 2019.04.04 |
Item 7. 델리게이트를 이용하여 콜백을 표현하라. (0) | 2019.03.27 |