우리가 같은 페이지에 있는지 확인하기 위해 메소드 "숨김"은 파생 클래스가 기본 클래스의 멤버와 동일한 이름의 멤버를 정의 할 때입니다 (메소드 / 프로퍼티 인 경우 가상 / 재정의 가능한 것으로 표시되지 않음) ), 파생 된 클래스의 인스턴스에서 "파생 된 컨텍스트"를 호출하면 파생 된 멤버가 사용되는 반면 기본 클래스의 컨텍스트에서 동일한 인스턴스를 호출하면 기본 클래스 멤버가 사용됩니다. 이것은 기본 클래스 멤버가 파생 클래스가 대체를 정의 할 것으로 예상하는 멤버 추상화 / 재정의와, 원하는 범위 밖의 소비자로부터 멤버를 "숨기는"범위 / 가시성 수정 자와 다릅니다.
허용되는 이유에 대한 짧은 대답은 그렇게하지 않으면 개발자가 객체 지향 디자인의 몇 가지 주요 원칙을 위반하게된다는 것입니다.
더 긴 대답은 다음과 같습니다. 먼저 C #에서 멤버 숨기기를 허용하지 않는 대체 유니버스에서 다음 클래스 구조를 고려하십시오.
public interface IFoo
{
string MyFooString {get;}
int FooMethod();
}
public class Foo:IFoo
{
public string MyFooString {get{return "Foo";}}
public int FooMethod() {//incredibly useful code here};
}
public class Bar:Foo
{
//public new string MyFooString {get{return "Bar";}}
}
Bar에서 멤버의 주석을 해제하고이를 통해 Bar가 다른 MyFooString을 제공하도록 허용하십시오. 그러나 멤버 숨기기에 대한 대체 현실 금지를 위반하기 때문에 그렇게 할 수 없습니다. 이 특정 예는 버그가 많지 않으며이를 금지하려는 주요 예입니다. 예를 들어, 다음을 수행하면 어떤 콘솔 출력을 얻을 수 있습니까?
Bar myBar = new Bar();
Foo myFoo = myBar;
IFoo myIFoo = myFoo;
Console.WriteLine(myFoo.MyFooString);
Console.WriteLine(myBar.MyFooString);
Console.WriteLine(myIFoo.MyFooString);
내 머리 꼭대기에서 실제로 마지막 줄에 "Foo"또는 "Bar"가 표시되는지 확실하지 않습니다. 세 변수가 모두 정확히 동일한 상태의 동일한 인스턴스를 참조하더라도 첫 번째 줄에는 "Foo", 두 번째 줄에는 "Bar"가 표시됩니다.
따라서 대체 우주에서 언어 디자이너는 속성 숨기기를 방지하여이 잘못된 코드를 사용하지 않는 것이 좋습니다. 이제 여러분은 코더로서 정확히이 일을해야합니다. 한계를 어떻게 극복합니까? 음, 한 가지 방법은 Bar의 속성 이름을 다르게 지정하는 것입니다.
public class Bar:Foo
{
public string MyBarString {get{return "Bar";}}
}
완벽하게 합법적이지만 우리가 원하는 행동은 아닙니다. Bar의 인스턴스는 "Bar"를 생성 할 때 MyFooString 속성에 대해 항상 "Foo"를 생성합니다. IFoo가 특별히 Bar라는 것을 알아야 할뿐만 아니라 다른 접근자를 사용해야한다는 것도 알아야합니다.
또한 부모-자식 관계를 잊고 인터페이스를 직접 구현할 수도 있습니다.
public class Bar:IFoo
{
public string MyFooString {get{return "Bar";}}
public int FooMethod() {...}
}
이 간단한 예를 들어 그것은 완벽한 대답 한으로 만 관심을 푸와 바 모두 IFoos이라는 것을. Bar가 Foo가 아니므로 할당 할 수 없으므로 몇 가지 예제를 사용하는 사용 코드가 컴파일되지 않습니다. 그러나 Foo에 Bar가 필요로하는 유용한 "FooMethod"메소드가있는 경우 해당 메소드를 상속 할 수 없습니다. Bar에서 코드를 복제하거나 창의성을 발휘해야합니다.
public class Bar:IFoo
{
public string MyFooString {get{return "Bar";}}
private readonly theFoo = new Foo();
public int FooMethod(){return theFoo.FooMethod();}
}
이것은 명백한 해킹이며, OO 언어 사양의 일부 구현은 이것보다 약간 더 중요하지만 개념적으로 잘못되었습니다. 바 필요의 소비자 푸의 기능을 노출하는 경우, 바한다 수 없습니다하는 푸 가 푸.
물론 Foo를 제어하면 가상으로 만든 다음 재정의 할 수 있습니다. 이것은 멤버가 재정의 될 것으로 예상 될 때 현재 유니버스에서 개념적인 모범 사례이며 숨기기를 허용하지 않는 대체 유니버스에서 유지됩니다.
public class Foo:IFoo
{
public virtual string MyFooString {get{return "Foo";}}
//...
}
public class Bar:Foo
{
public override string MyFooString {get{return "Bar";}}
}
이것의 문제점은 가상 멤버 액세스가 수행 비용이 상대적으로 비싸기 때문에 일반적으로 필요할 때만 수행한다는 것입니다. 그러나 숨기지 않으면 소스 코드를 제어하지 않는 다른 코더가 다시 구현하기를 원할 수있는 멤버에 대해 비관적이어야합니다. 봉인되지 않은 클래스의 "모범 사례"는 특별히 원하지 않는 한 모든 것을 가상으로 만드는 것입니다. 또한 여전히 숨어있는 정확한 행동을 제공하지는 않습니다. 인스턴스가 Bar 인 경우 문자열은 항상 "Bar"입니다. 때로는 작업중인 상속 수준에 따라 숨겨진 상태 데이터 계층을 활용하는 것이 진정으로 유용한 경우가 있습니다.
요약하면, 멤버 숨기기를 허용하는 것이 이러한 악의 적은 것입니다. 그것을 갖지 않으면 일반적으로 그것을 허용하는 것보다 객체 지향적 원칙에 반하는 더 나쁜 잔학 행위로 이어질 것입니다.