상속된 클래스(기본 클래스)를 수정하지 않고 클래스에서 상속된 속성을 숨기는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/1875401

문제

다음 코드 예제가 있는 경우:

public class ClassBase
{
    public int ID { get; set; }

    public string Name { get; set; }
}

public class ClassA : ClassBase
{
    public int JustNumber { get; set; }

    public ClassA()
    {
        this.ID = 0;
        this.Name = string.Empty;
        this.JustNumber = string.Empty;
    }
}

재산을 숨기려면 어떻게 해야 하나요? Name (ClassA 멤버로는 표시되지 않습니다) 수정 없이 ClassBase ?

도움이 되었습니까?

해결책

나는 여기서 코드 냄새 냄새가납니다. 기본 클래스의 모든 기능을 구현하는 경우 기본 클래스 만 상속해야한다고 생각합니다. 당신이하는 일은 실제로 객체 지향 원리를 올바르게 나타내지 않습니다. 따라서 기지에서 상속을 받으려면 이름을 구현해야합니다. 그렇지 않으면 상속 재산이 잘못된 길을 얻었습니다. 클래스 A는 기본 클래스 여야하며 현재 기본 클래스는 다른 방법이 아니라 원하는 경우에서 상속해야합니다.

하지만, 직접적인 질문에서 너무 멀리 길을 잃지 마십시오. 만약 너라면 했다 "규칙"을 무시하고 선택한 길을 계속하고 싶다 - 여기에 갈 수있는 방법은 다음과 같습니다.

이 협약은 속성을 구현하는 것이지만 해당 속성이 호출 될 때 명백한 지출을 던지는 것입니다. 그러나 그것은 나의 개인적인 의견이며,이 협약이 여전히 존재한다는 사실을 바꾸지 않습니다.

속성을 사용하지 않으려는 경우 (그리고 기본 클래스에서 가상으로 선언 된 경우), 당신은 그것에 쓸모없는 속성을 사용할 수 있습니다.

[Obsolete("This property has been deprecated and should no longer be used.", true)]
public override string Name 
{ 
    get 
    { 
        return base.Name; 
    }
    set
    {
        base.Name = value;
    }
}

(편집하다: Brian이 주석에서 지적했듯이, 속성의 두 번째 매개 변수는 누군가가 속성을 참조하면 컴파일러 오류가 발생하므로 파생 클래스에서 구현하더라도 사용할 수 없습니다.)

또는 내가 언급했듯이 NotimplementedException 사용 :

public override string Name
{
    get
    {
        throw new NotImplementedException();
    }
    set
    {
        throw new NotImplementedException();
    }
}

그러나 재산 인 경우 그렇지 않습니다 가상으로 선언 된 다음 새 키워드를 사용하여 대체 할 수 있습니다.

public new string Name
{
    get
    {
        throw new NotImplementedException();
    }
    set
    {
        throw new NotImplementedException();
    }
}

메소드가 재정의 된 것과 같은 방식으로 더 이상 사용되지 않는 속성을 사용할 수 있거나 선택한 사람이든지 알 수없는 exception을 던질 수 있습니다. 아마 사용할 것입니다 :

[Obsolete("Don't use this", true)]
public override string Name { get; set; }

또는:

[Obsolete("Don't use this", true)]
public new string Name { get; set; }

기본 클래스에서 가상으로 선언되었는지 여부에 따라

다른 팁

기술적으로 부동산은 숨겨지지 않지만, 사용을 강력하게 낙담시키는 한 가지 방법은 다음과 같이 속성을 배치하는 것입니다.

[Browsable(false)]
[Bindable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[EditorBrowsable(EditorBrowsableState.Never)]

이것이 System.windows.forms가 적합하지 않은 속성이있는 컨트롤을 위해 수행하는 것입니다. 그만큼 텍스트 예를 들어, 속성은 통제 중이지만 모든 클래스에서 제어에서 물려받는 것은 의미가 없습니다. 그래서 MonthCalendar, 예를 들어, 텍스트 속성은 다음과 같이 나타납니다 (온라인 참조 소스에 따라).

[Browsable(false),
    EditorBrowsable(EditorBrowsableState.Never),
    Bindable(false), 
    DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text {
    get { return base.Text; }
    set { base.Text = value; }
}
  • 눈썹 - 멤버가 속성 창에 표시되는지 여부
  • 편집자가 가능합니다 - 회원이 Intellisense 드롭 다운에 나타나는지 여부

EditorBrowsable (False)은 속성을 입력하는 것을 방해하지 않으며 속성을 사용하는 경우 프로젝트가 여전히 컴파일됩니다. 그러나 재산은 Intellisense에 나타나지 않기 때문에 사용할 수 있다는 것은 분명하지 않습니다.

그냥 숨기세요

 public class ClassBase
{
    public int ID { get; set; }
    public string Name { get; set; }
}
public class ClassA : ClassBase
{
    public int JustNumber { get; set; }
    private new string Name { get { return base.Name; } set { base.Name = value; } }
    public ClassA()
    {
        this.ID = 0;
        this.Name = string.Empty;
        this.JustNumber = 0;
    }
}

메모:Name은 여전히 ​​ClassBase의 공개 멤버가 될 것입니다. 기본 클래스를 변경하지 않는다는 제약 조건을 고려할 때 이를 막을 수 있는 방법은 없습니다.

필요하지 않을 때 왜 상속을 강요합니까? 올바른 방법은 has-a 대신 a IS-A.

public class ClassBase
{
    public int ID { get; set; }

    public string Name { get; set; }
}

public class ClassA
{
    private ClassBase _base;

    public int ID { get { return this._base.ID; } }

    public string JustNumber { get; set; }

    public ClassA()
    {
        this._base = new ClassBase();
        this._base.ID = 0;
        this._base.Name = string.Empty;
        this.JustNumber = string.Empty;
    }
}

나는 속성이 기본 클래스에서 제거되어서는 안된다는 데 전적으로 동의하지만 때로는 파생 클래스가 값을 입력하는 다른 적절한 방법을 가질 수 있습니다. 예를 들어, 제 경우에는 ItemsControl에서 상속됩니다. 우리 모두가 알고 있듯이 ItimsControl에는 itemsSource 속성이 있지만 제어 제어는 두 소스 (예 : 사람 및 위치)의 데이터를 병합하려고합니다. 항목 소스를 사용하여 사용자가 데이터를 입력하도록하려면 값을 분리 한 다음 재결합해야하므로 데이터를 입력하기 위해 2 개의 속성을 만들었습니다. 그러나 원래의 질문으로 돌아가서, 이것은 ItemsSource를 남겨두고, 나는 내 자신의 속성으로 그것을 "교체"하기 때문에 사용자가 사용하기를 원하지 않습니다. 나는 눈썹과 편집기 브라우즈 가능한 아이디어를 좋아하지만 여전히 사용자가 그것을 사용하지 못하게하지는 않습니다. 여기서 기본 요점은 상속이 대부분의 속성을 유지해야한다는 것입니다. 그러나 큰 복잡한 클래스 (특히 원래 코드를 수정할 수없는 클래스가있는 경우)가 있으면 모든 것을 다시 쓰는 것이 매우 비효율적입니다.

나는 여기에 대답하는 많은 사람들이 상속을 전혀 이해하지 못한다고 생각합니다. 기본 클래스에서 상속하고 한 번 공개 var와 기능을 숨겨야합니다. 예를 들어, 기본 엔진이 있고 과급 된 새 엔진을 만들고 싶다고 가정 해 봅시다. 글쎄, 당신이 사용할 엔진의 99%가 사용하지만 훨씬 더 잘 실행되도록 약간의 기능을 조정하지만 여전히 최종 사용자가 아닌 수정에만 표시되는 기능이 있습니다. 우리 모두는 모든 클래스 MS가 내놓는 것이 실제로 수정이 필요하지 않다는 것을 알고 있기 때문입니다.

새로운 기능을 사용하는 것 외에도 기능을 무시하는 것 외에도 Microsoft가 무한한 위스로 인한 것 중 하나입니다.

이를 달성하는 가장 좋은 방법은 다단계 상속입니다.

public class classA 
{
}

public class B : A 
{} 

public class C : B 
{} 

클래스 B는 모든 작업을 수행하고 클래스 C는 노출 된 내용을 노출시킵니다.

당신은 그것이 상속의 요점입니다 : 서브 클래스는 기본 클래스의 모든 방법과 속성을 제공해야합니다.

속성을 호출 할 때 (가상 인 경우), 구현을 변경할 수 있습니다 ...

이 작업을 수행해야한다면, 특히 처음부터 코드를 디자인 할 수 있다면 디자인이 좋지 않다고 생각합니다.

왜요?

좋은 디자인은 기본 클래스가 특정 개념 (가상 또는 실제)의 공통 속성을 공유하도록하는 것입니다. 예 : C#의 System.io.Stream.

차선 나쁜 디자인을 더 아래로 내려 가면 유지 보수 비용이 증가하고 구현을 더 어렵고 더 어렵게 만듭니다. 이것을 최대한 피하십시오!

내가 사용하는 기본 규칙 :

  • 기본 클래스의 속성 및 메소드 수를 최소화하십시오. 기본 클래스를 상속하는 클래스에서 일부 속성이나 메소드를 사용하지 않을 경우; 그럼베이스 클래스에 넣지 마십시오. 프로젝트의 개발 단계에 있다면; 항상 드로잉 보드로 돌아가서 상황이 바뀌기 때문에 디자인을 확인하십시오! 필요할 때 재 설계하십시오. 프로젝트가 실시되면 디자인 후반에 물건을 바꾸는 데 드는 비용이 올라갑니다!

    • 3 : RD 당사자가 구현 한베이스 클래스를 사용하는 경우 "NotimplementedException"또는 그와 함께 "재정의"대신 "Go Up"을 고려하십시오. 다른 레벨이 없으면 코드를 처음부터 디자인하는 것을 고려하십시오.

    • 누구나 상속받을 수없는 클래스를 봉인하는 것을 항상 고려하십시오. 코더는 "상속- 계층 구조"에서 "한 레벨을 올라"도록 강요하므로 "NotimplementedException"과 같은 "느슨한 끝"을 피할 수 있습니다.

나는 질문이 오래되었다는 것을 알고 있지만, 당신이 할 수있는 일은 다음과 같은 postfilterproperties를 무시하는 것입니다.

 protected override void PostFilterProperties(System.Collections.IDictionary properties)
    {
        properties.Remove("AccessibleDescription");
        properties.Remove("AccessibleName");
        properties.Remove("AccessibleRole");
        properties.Remove("BackgroundImage");
        properties.Remove("BackgroundImageLayout");
        properties.Remove("BorderStyle");
        properties.Remove("Cursor");
        properties.Remove("RightToLeft");
        properties.Remove("UseWaitCursor");
        properties.Remove("AllowDrop");
        properties.Remove("AutoValidate");
        properties.Remove("ContextMenuStrip");
        properties.Remove("Enabled");
        properties.Remove("ImeMode");
        //properties.Remove("TabIndex"); // Don't remove this one or the designer will break
        properties.Remove("TabStop");
        //properties.Remove("Visible");
        properties.Remove("ApplicationSettings");
        properties.Remove("DataBindings");
        properties.Remove("Tag");
        properties.Remove("GenerateMember");
        properties.Remove("Locked");
        //properties.Remove("Modifiers");
        properties.Remove("CausesValidation");
        properties.Remove("Anchor");
        properties.Remove("AutoSize");
        properties.Remove("AutoSizeMode");
        //properties.Remove("Location");
        properties.Remove("Dock");
        properties.Remove("Margin");
        properties.Remove("MaximumSize");
        properties.Remove("MinimumSize");
        properties.Remove("Padding");
        //properties.Remove("Size");
        properties.Remove("DockPadding");
        properties.Remove("AutoScrollMargin");
        properties.Remove("AutoScrollMinSize");
        properties.Remove("AutoScroll");
        properties.Remove("ForeColor");
        //properties.Remove("BackColor");
        properties.Remove("Text");
        //properties.Remove("Font");
    }

당신이 사용할 수있는 Browsable(false)

[Browsable( false )]
public override string Name
{
    get { return base.Name; }
    set { base.Name= value; }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top